├── LICENSE.txt ├── Makefile ├── README.md ├── bin └── README.md ├── build_dynamic_lib.bat ├── build_gui_debug.bat ├── build_gui_release.bat ├── build_static_lib.bat ├── examples ├── sponza.f └── vase.f ├── libf ├── ao.f ├── basic.f ├── compose.f ├── geometry.f ├── hg_sdf.f └── publication.f ├── python ├── README.md └── fraktal │ └── __init__.py ├── res ├── fraktal-logo-source.svg ├── fraktal-logo.svg ├── icon.ico └── resources.rc └── src ├── fraktal.cpp ├── fraktal.h ├── fraktal_array.h ├── fraktal_context.h ├── fraktal_kernel.h ├── fraktal_link.h ├── fraktal_parse.h ├── fraktal_types.h ├── gui.cpp ├── reuse ├── args.h ├── file.h ├── gl3w │ └── GL │ │ ├── gl3w.c │ │ ├── gl3w.h │ │ └── glcorearb.h ├── glfw │ ├── COPYING.txt │ ├── include │ │ └── GLFW │ │ │ ├── glfw3.h │ │ │ └── glfw3native.h │ ├── lib-vc2010-32 │ │ └── glfw3.lib │ └── lib-vc2010-64 │ │ └── glfw3.lib ├── imgui │ ├── LICENSE.txt │ ├── imconfig.h │ ├── imgui.cpp │ ├── imgui.h │ ├── imgui_demo.cpp │ ├── imgui_draw.cpp │ ├── imgui_impl_glfw.cpp │ ├── imgui_impl_glfw.h │ ├── imgui_impl_opengl3.cpp │ ├── imgui_impl_opengl3.h │ ├── imgui_internal.h │ ├── imgui_widgets.cpp │ ├── imstb_rectpack.h │ ├── imstb_textedit.h │ └── imstb_truetype.h ├── imgui_extensions.h ├── jsmn.h ├── log.h ├── open_sans_regular.h ├── open_sans_semi_bold.h ├── stb_image.h └── stb_image_write.h └── widgets ├── Camera.h ├── Geometry.h ├── Ground.h ├── Material.h ├── Sun.h ├── Widget.h └── colormap_inferno.h /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2019 Simen Haugo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Cross Platform Makefile 3 | # Compatible with MSYS2/MINGW, Ubuntu 14.04.1 and Mac OS X 4 | # 5 | # You will need GLFW (http://www.glfw.org): 6 | # Linux: 7 | # apt-get install libglfw3-dev 8 | # Mac OS X: 9 | # brew install glfw 10 | # MSYS2: 11 | # pacman -S --noconfirm --needed mingw-w64-x86_64-toolchain mingw-w64-x86_64-glfw 12 | # 13 | 14 | #CXX = g++ 15 | #CXX = clang++ 16 | 17 | EXE = bin/fraktal 18 | UNAME_S := $(shell uname -s) 19 | 20 | CXXFLAGS = -I./src/reuse/gl3w -I./src/reuse -I./src/reuse/glfw/include -I./src/reuse/imgui 21 | 22 | ##--------------------------------------------------------------------- 23 | ## BUILD FLAGS PER PLATFORM 24 | ##--------------------------------------------------------------------- 25 | 26 | ifeq ($(UNAME_S), Linux) #LINUX 27 | ECHO_MESSAGE = "Linux" 28 | LIBS = -lGL `pkg-config --static --libs glfw3` 29 | 30 | CXXFLAGS += `pkg-config --cflags glfw3` 31 | CXXFLAGS += -std=c++11 -Wall -Wformat 32 | CFLAGS = $(CXXFLAGS) 33 | endif 34 | 35 | ifeq ($(UNAME_S), Darwin) #APPLE 36 | ECHO_MESSAGE = "Mac OS X" 37 | LIBS = -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo 38 | #LIBS += -L/usr/local/lib -lglfw3 39 | LIBS += -L/usr/local/lib -lglfw 40 | 41 | CXXFLAGS += -I/usr/local/include 42 | CXXFLAGS += -std=c++11 -Wall -Wformat 43 | CFLAGS = $(CXXFLAGS) 44 | endif 45 | 46 | ifeq ($(findstring MINGW,$(UNAME_S)),MINGW) 47 | ECHO_MESSAGE = "Windows" 48 | LIBS = -lglfw3 -lgdi32 -lopengl32 -limm32 49 | 50 | CXXFLAGS += `pkg-config --cflags glfw3` 51 | CXXFLAGS += -std=c++11 -Wall -Wformat 52 | CFLAGS = $(CXXFLAGS) 53 | endif 54 | 55 | ##--------------------------------------------------------------------- 56 | ## BUILD RULES 57 | ##--------------------------------------------------------------------- 58 | 59 | all: src/gui.cpp 60 | $(CXX) src/gui.cpp $(CXXFLAGS) $(LIBS) -o $(EXE) 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | Fraktal is a software library for procedural function-based representations (FRep) aimed at facilitating computer vision and machine learning research. It is designed to aid research in using the FRep in such applications as: 6 | 7 | * 3D reconstruction 8 | * Inverse rendering / procedural modeling / program synthesis 9 | * Learning generative models 10 | * Generating ground-truth synthetic datasets 11 | 12 | The core library is a GPU-accelerated FRep evaluator bundled with several utilities: 13 | 14 | * Procedures for common primitives, transformations and CSG operators 15 | * Procedures for surface normal evaluation and accelerated ray-surface intersection 16 | * Physically-based path tracer for FReps 17 | * Multi-target (Depth + Normals + Thickness) rendering 18 | 19 | Fraktal also comes with a graphical application, which lets you visualize and live-edit FReps or adjust camera and scene parameters. The bundled renderer uses a novel de-noising algorithm that lets you create publication-quality figures quickly. 20 | 21 | ## Requirements 22 | 23 | The core library provides GPU-acceleration on the major hardware platforms: NVIDIA, AMD and Intel integrated graphics. At minimum, you need a GPU, a driver with OpenGL 3.1 support (most platforms, including MacBook laptops, meet these requirements) and [glfw](https://www.glfw.org/) installed. 24 | 25 | ## Screenshots 26 | 27 | The interactive FRep viewer: 28 | 29 |

30 | 31 |

32 | 33 |

34 | 35 |

36 | 37 | Note that the core library is not limited to evaluating the function densely over an image, but can also be run on arbitrary input sets, such as point clouds or sparse pixels. 38 | 39 | ## Installation 40 | 41 | ### C/C++ library 42 | The core library can be compiled from source into a static or dynamic library using the appropriate build script for your platform: 43 | 44 | * Windows: build_static_lib.bat or build_dynamic_lib.bat 45 | * Linux/MacOS: make 46 | 47 | ### GUI 48 | The GUI application can be compiled from source using the appropriate build script for your platform: 49 | 50 | * Windows: build_gui.bat 51 | * Linux/MacOS: make 52 | 53 | ### Python bindings 54 | Python bindings can be found in the [python](python) directory. See that directory's readme for installation instructions. 55 | 56 | ## About Function Representations 57 | 58 | A Function Representation (FRep) is a function that converts a 3D coordinate to a scalar, whose sign determines whether the given point is inside or outside the surface. In C, it would have the following declaration: 59 | 60 | ``` 61 | float f(float x, float y, float z) 62 | ``` 63 | 64 | In general f can be an arbitrary computer program, using conditionals, loops, variable declarations and mathematical expression. However, the FRep framework supports a number of high-level modeling operations (which are again defined procedurally), such as 65 | 66 | * Geometric primitives 67 | * Boolean combination 68 | * Rigid-body transformation 69 | * Repetition and mirroring 70 | * Bending, twisting and other deformations 71 | 72 | These can be combined hierarchically to construct complex shapes or define a library of higher-level primitives that can be reused in other models. 73 | 74 | To learn more about FReps, and procedural modeling in general, I recommend the following resources: 75 | 76 | * [Wikipedia](https://en.wikipedia.org/wiki/Function_representation) 77 | * [HyperFun](http://www.hyperfun.org/F-rep.html) 78 | * A. Pasko, V. Adzhiev, A. Sourin and V. Savchenko. Function Representation in Geometric Modeling: Concepts, Implementation and Applications. 1995. 79 | * [J. Snyder and J. Kajiya. Generative Modeling: A Symbolic System for Geometric Modeling. 1992. ](https://ohiostate.pressbooks.pub/app/uploads/sites/45/2017/09/generative-snyder-kajiya.pdf) 80 | -------------------------------------------------------------------------------- /bin/README.md: -------------------------------------------------------------------------------- 1 | Compiled binaries go here. -------------------------------------------------------------------------------- /build_dynamic_lib.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. 3 | 4 | if not exist "lib" mkdir lib 5 | pushd lib 6 | 7 | del *.obj 8 | del *.lib 9 | del *.exp 10 | del *.pdb 11 | 12 | set INCLUDES=/I..\src\reuse /I..\src\reuse\glfw\include /I..\src\reuse\gl3w 13 | set LIBS=/LIBPATH:..\src\reuse\glfw\lib-vc2010-32 14 | cl ..\src\fraktal.cpp /nologo /DFRAKTAL_BUILD_DLL /MD /W3 /WX /LD %INCLUDES% /link %LIBS% glfw3.lib gdi32.lib shell32.lib user32.lib opengl32.lib /out:fraktal.dll 15 | 16 | popd 17 | -------------------------------------------------------------------------------- /build_gui_debug.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. 3 | 4 | pushd bin 5 | 6 | set INCLUDES=/I..\src\reuse /I..\src\reuse\glfw\include /I..\src\reuse\gl3w /I..\src\reuse\imgui 7 | set CFLAGS=/nologo /Zi /MD /W3 /WX /D_CRT_SECURE_NO_WARNINGS 8 | set LIBS=/LIBPATH:..\src\reuse\glfw\lib-vc2010-32 glfw3.lib opengl32.lib gdi32.lib shell32.lib user32.lib 9 | cl ..\src\gui.cpp %CFLAGS% %INCLUDES% /link %LIBS% /out:fraktal.exe 10 | 11 | popd 12 | 13 | if not errorlevel 1 bin\fraktal.exe 14 | -------------------------------------------------------------------------------- /build_gui_release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Run your copy of 64-bit vcvarsall.bat to setup command-line compiler. 3 | 4 | pushd bin 5 | 6 | REM This packs the application icon into a resource.res file, which gets linked in to the final exe 7 | rc -nologo ..\res\resources.rc 8 | 9 | set INCLUDES=/I..\src\reuse /I..\src\reuse\glfw\include /I..\src\reuse\gl3w /I..\src\reuse\imgui 10 | set CFLAGS=/nologo /MD /W3 /WX /O2 /D_CRT_SECURE_NO_WARNINGS 11 | set LIBS=/LIBPATH:..\src\reuse\glfw\lib-vc2010-64 glfw3.lib opengl32.lib gdi32.lib shell32.lib user32.lib 12 | set LFLAGS=/MACHINE:X64 /subsystem:CONSOLE ..\res\resources.res 13 | cl ..\src\gui.cpp %CFLAGS% %INCLUDES% /link %LIBS% %LFLAGS% /out:fraktal.exe 14 | 15 | popd 16 | 17 | if not errorlevel 1 bin\fraktal.exe 18 | -------------------------------------------------------------------------------- /build_static_lib.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. 3 | REM When linking against fraktal.lib in your application you also need to link against glfw3.lib gdi32.lib shell32.lib user32.lib opengl32.lib 4 | 5 | if not exist "lib" mkdir lib 6 | pushd lib 7 | 8 | del *.obj 9 | del *.lib 10 | del *.exp 11 | del *.pdb 12 | 13 | set INCLUDES=/I..\src\reuse /I..\src\reuse\glfw\include /I..\src\reuse\gl3w 14 | cl ..\src\fraktal.cpp /c /nologo /MD /W3 /WX %INCLUDES% 15 | lib fraktal.obj /nologo /out:fraktal.lib 16 | 17 | popd 18 | -------------------------------------------------------------------------------- /examples/sponza.f: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | float model(vec3 p) { 5 | vec3 p0 = p; 6 | float d; 7 | p.x = -abs(p.x) + 1.2; 8 | vec3 q = p; 9 | { 10 | pModInterval1(q.z, 1.1, -3.0, +3.0); 11 | d = fCylinder(q.yxz, 0.5, 0.75); 12 | q = p; 13 | d = min(d, fCylinder(q.yzx, 0.5, 3.8)); 14 | d = max(d, -p.y); 15 | q.y -= 0.32; 16 | d = max(fBox(q, vec3(0.6, 0.3, 4.0)), -d); 17 | } 18 | { 19 | q = p; 20 | q.z -= 0.55; 21 | pModInterval1(q.z, 1.1, -4.0, +3.0); 22 | q.x -= 0.55; 23 | d = min(d, fBox(q, vec3(0.08,0.02,0.08))); 24 | q.y += 0.25; 25 | d = min(d, fCylinder(q, 0.06, 0.25)); 26 | } 27 | 28 | { 29 | q = p; 30 | q.y -= 1.25; 31 | pModInterval1(q.z, 1.1, -3.0, +3.0); 32 | float d1 = fCylinder(q.yxz, 0.5, 0.75); 33 | d1 = min(d1, fCylinder(q.yzx, 0.5, 3.8)); 34 | d1 = max(d1, -p.y); 35 | q.y -= 0.32; 36 | // d = min(d, fBox(q, vec3(0.48, 0.3, 3.78))); 37 | d1 = max(fBox(q, vec3(0.6, 0.3, 4.0)), -d1); 38 | d = min(d, d1); 39 | } 40 | { 41 | q = p; 42 | q.y -= 1.25; 43 | q.z -= 0.55; 44 | pModInterval1(q.z, 1.1, -4.0, +3.0); 45 | q.x -= 0.55; 46 | d = min(d, fBox(q, vec3(0.08,0.01,0.08))); 47 | q.y += 0.25; 48 | d = fOpUnionSoft(d, fBox(q, vec3(0.04, 0.25, 0.04)), 0.05); 49 | } 50 | { 51 | q = p; 52 | q.y -= 0.7; 53 | q.x -= 0.5; 54 | d = min(d, fBox(q, vec3(0.1,0.1,4.0))); 55 | } 56 | { 57 | d = min(d, p.x + 0.5); 58 | d = max(d, -p.x - 3.0); 59 | d = min(d, p.z + 4.0); 60 | d = max(d, p0.z - 2.0); 61 | d = max(d, p.y - 2.0); 62 | d = min(d, p.y + 0.5); 63 | } 64 | 65 | d = fOpUnionSoft(d, length(p0 - vec3(0.0,0.6,0.0)) - 0.5, 0.5); 66 | p0.y -= 0.6; 67 | d = max(d, -fCylinder(p0.yzx, 0.3, 2.0)); 68 | 69 | return d; 70 | } 71 | -------------------------------------------------------------------------------- /examples/vase.f: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | float model(vec3 p) { 5 | float d = fSphere(p, 0.5); 6 | 7 | // grooves 8 | vec3 q = p; 9 | float t = q.y + 0.5; 10 | q.xz = pOpRotate(q.xz, -smoothstep(0.0,0.5,0.5*t)*0.7); 11 | float a = atan(q.z, q.x); 12 | d -= 0.03*sin(14.0*a); 13 | d *= 0.5; // Lipschitz factor 14 | 15 | // Top 16 | p.y -= 0.5; 17 | d = fOpUnionSoft(d, fCylinder(p, 0.2, 1.0), 0.3); 18 | p.y -= 1.0; 19 | d = fOpUnionSoft(d, fCylinder(p, 0.3, 0.01), 0.1); 20 | float inside = fCylinder(p, 0.18, 1.2); 21 | p.y += 1.5; 22 | inside = fOpUnionSoft(inside, fSphere(p, 0.4), 0.3); 23 | d = max(d, -inside); 24 | 25 | return d; 26 | } 27 | -------------------------------------------------------------------------------- /libf/ao.f: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | uniform vec2 iResolution; 5 | uniform vec2 iCameraCenter; 6 | uniform float iCameraF; 7 | uniform mat4 iView; 8 | uniform int iSamples; 9 | out vec4 fragColor; 10 | 11 | #define EPSILON 0.0001 12 | #define STEPS 512 13 | #define DENOISE 1 14 | #define MAX_DISTANCE 100.0 15 | #define MAX_AO_DISTANCE 1.0 16 | #define M_PI 3.1415926535897932384626433832795 17 | 18 | float model(vec3 p); // forward-declaration 19 | 20 | #if DENOISE 21 | vec2 seed = vec2(-1,1)*(iSamples*(1.0/12.0) + 1.0); 22 | #else 23 | vec2 seed = (vec2(-1.0) + 2.0*gl_FragCoord.xy/iResolution.xy)*(iSamples*(1.0/12.0) + 1.0); 24 | #endif 25 | vec2 noise2f() 26 | { 27 | // lumina.sourceforge.net/Tutorials/Noise.html 28 | seed += vec2(-1, 1); 29 | return vec2(fract(sin(dot(seed.xy, vec2(12.9898, 78.233))) * 43758.5453), 30 | fract(cos(dot(seed.xy, vec2(4.898, 7.23))) * 23421.631)); 31 | } 32 | 33 | vec3 cosineWeightedSample(vec3 normal) 34 | { 35 | vec2 u = noise2f(); 36 | float a = 0.99*(1.0 - 2.0*u[0]); 37 | float b = 0.99*(sqrt(1.0 - a*a)); 38 | float phi = 6.2831853072*u[1]; 39 | float x = normal.x + b*cos(phi); 40 | float y = normal.y + b*sin(phi); 41 | float z = normal.z + a; 42 | return normalize(vec3(x,y,z)); 43 | } 44 | 45 | vec3 rayPinhole(vec2 fragOffset) 46 | { 47 | vec2 uv = vec2(gl_FragCoord.x, iResolution.y - gl_FragCoord.y) + fragOffset - iCameraCenter; 48 | float d = 1.0/length(vec3(uv, iCameraF)); 49 | return vec3(uv*d, -iCameraF*d); 50 | } 51 | 52 | // http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm 53 | vec3 normal(vec3 p) 54 | { 55 | const float ep = 0.0001; 56 | vec2 e = vec2(1.0,-1.0)*0.5773*ep; 57 | return normalize( e.xyy*model( p + e.xyy ) + 58 | e.yyx*model( p + e.yyx ) + 59 | e.yxy*model( p + e.yxy ) + 60 | e.xxx*model( p + e.xxx ) ); 61 | } 62 | 63 | float trace(vec3 ro, vec3 rd) 64 | { 65 | float t = 0.0; 66 | for (int i = ZERO; i < STEPS; i++) 67 | { 68 | vec3 p = ro + t*rd; 69 | float d = model(p); 70 | if (d <= EPSILON) return t; 71 | t += d; 72 | if (t > MAX_DISTANCE) break; 73 | } 74 | return -1.0; 75 | } 76 | 77 | float ambientOcclusion(vec3 p) 78 | { 79 | vec3 n = normal(p); 80 | vec3 ro = p + 2.0*EPSILON*n; 81 | vec3 rd = cosineWeightedSample(n); 82 | float t = 0.0; 83 | for (int i = ZERO; i < STEPS && t < MAX_AO_DISTANCE; i++) 84 | { 85 | vec3 p = ro + t*rd; 86 | float d = model(p); 87 | t += d; 88 | if (d <= EPSILON) 89 | return 0.0; 90 | } 91 | return 1.0; 92 | } 93 | 94 | void main() 95 | { 96 | vec3 rd = rayPinhole(noise2f()); 97 | vec3 ro = (iView * vec4(0.0, 0.0, 0.0, 1.0)).xyz; 98 | rd = normalize((iView * vec4(rd, 0.0)).xyz); 99 | 100 | fragColor = vec4(1.0); 101 | float t = trace(ro, rd); 102 | if (t > 0.0) 103 | fragColor.rgb = vec3(1.0)*ambientOcclusion(ro + t*rd); 104 | } 105 | -------------------------------------------------------------------------------- /libf/basic.f: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | uniform vec2 iLowResolution; 5 | uniform vec2 iResolution; 6 | uniform vec2 iCameraCenter; 7 | uniform float iCameraF; 8 | uniform float iGroundHeight; 9 | uniform mat4 iView; 10 | uniform int iSamples; 11 | uniform sampler2D iChannel0; 12 | uniform int iMode; 13 | out vec4 fragColor; 14 | 15 | #define EPSILON 0.0007 16 | #define STEPS 512 17 | #define MAX_DISTANCE 100.0 18 | #define INFINITY (9999999999.0) 19 | #define MAX_AO_DISTANCE 1.0 20 | #define M_PI 3.1415926535897932384626433832795 21 | 22 | float model(vec3 p); // forward-declaration 23 | 24 | // lumina.sourceforge.net/Tutorials/Noise.html 25 | vec2 seed = vec2(-1,1)*(iSamples*(1.0/12.0) + 1.0); 26 | vec2 noise2f() 27 | { 28 | seed += vec2(-1, 1); 29 | return vec2(fract(sin(dot(seed.xy, vec2(12.9898, 78.233))) * 43758.5453), 30 | fract(cos(dot(seed.xy, vec2(4.898, 7.23))) * 23421.631)); 31 | } 32 | 33 | // http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm 34 | vec3 normalModel(vec3 p) 35 | { 36 | const float ep = 0.0001; 37 | vec2 e = vec2(1.0,-1.0)*0.5773*ep; 38 | return normalize( e.xyy*model( p + e.xyy ) + 39 | e.yyx*model( p + e.yyx ) + 40 | e.yxy*model( p + e.yxy ) + 41 | e.xxx*model( p + e.xxx ) ); 42 | } 43 | 44 | float traceModel(vec3 ro, vec3 rd, float t) 45 | { 46 | for (int i = ZERO; i < STEPS; i++) 47 | { 48 | vec3 p = ro + t*rd; 49 | float d = model(p); 50 | if (d <= EPSILON) return t; 51 | t += d; 52 | if (t > MAX_DISTANCE) return INFINITY; 53 | } 54 | return INFINITY; 55 | } 56 | 57 | float traceGround(vec3 ro, vec3 rd) 58 | { 59 | if (rd.y >= 0.0) return INFINITY; 60 | else return (iGroundHeight - ro.y)/rd.y; 61 | } 62 | 63 | vec3 normalGround(vec3 p) 64 | { 65 | return vec3(0.0, 1.0, 0.0); 66 | } 67 | 68 | // from https://www.shadertoy.com/view/3lsSzf 69 | float occlusion( in vec3 pos, in vec3 nor ) 70 | { 71 | float occ = 0.0; 72 | float sca = 1.0; 73 | for( int i=ZERO; i<5; i++ ) 74 | { 75 | float h = 0.01 + 0.11*float(i)/4.0; 76 | vec3 opos = pos + h*nor; 77 | float d = min(opos.y - iGroundHeight, model(opos)); 78 | occ += (h-d)*sca; 79 | sca *= 0.95; 80 | } 81 | return clamp( 1.0 - 2.0*occ, 0.0, 1.0 ); 82 | } 83 | 84 | float visibility(in vec3 ro, in vec3 n, in vec3 rd) 85 | { 86 | if (traceGround(ro + 2.0*EPSILON*n, rd) < INFINITY) 87 | return 0.0; 88 | if (traceModel(ro + 2.0*EPSILON*n, rd, 0.0) < INFINITY) 89 | return 0.0; 90 | return 1.0; 91 | } 92 | 93 | float checkerboard(vec3 p) 94 | { 95 | return mod(floor(p.x) + floor(p.y + 0.001) + floor(p.z), 2.0); 96 | } 97 | 98 | vec3 materialGround(vec3 p) 99 | { 100 | // return vec3(0.07); 101 | return mix(vec3(0.1), vec3(0.12), checkerboard(p)); 102 | } 103 | 104 | vec3 materialModel(vec3 p) 105 | { 106 | // return vec3(0.1,0.03,0.02); 107 | return vec3(0.07,0.06,0.07)*mix(1.0, 1.3, checkerboard(p*4.0)); 108 | } 109 | 110 | vec3 render(vec3 ro, vec3 rd, float t) 111 | { 112 | float tg = traceGround(ro, rd); 113 | float tm = traceModel(ro, rd, t); 114 | vec3 n,m,p; 115 | if (tg < tm) 116 | { 117 | p = ro + tg*rd; 118 | n = normalGround(p); 119 | m = materialGround(p); 120 | } 121 | else if (tm < tg) 122 | { 123 | p = ro + tm*rd; 124 | n = normalModel(p); 125 | m = materialModel(p); 126 | } 127 | else 128 | { 129 | return vec3(1.0); 130 | } 131 | 132 | vec3 col = vec3(0.0); 133 | vec3 sun = normalize(vec3(0.2, 1.0, 0.5)); 134 | col += max(dot(n, sun), 0.0)*visibility(p, n, sun)*vec3(8.1,6.0,4.2); 135 | col += vec3(0.3,0.5,0.7)*occlusion(p, n); 136 | col *= m; 137 | return col; 138 | } 139 | 140 | void main() 141 | { 142 | if (iMode == 1) 143 | { 144 | vec2 scale = iResolution.xy/iLowResolution.xy; 145 | vec2 fragCoord = gl_FragCoord.xy*scale; 146 | vec2 uv = vec2(fragCoord.x, iResolution.y - fragCoord.y) - iCameraCenter; 147 | vec3 rd = normalize(vec3(uv, -iCameraF)); 148 | vec3 ro = (iView * vec4(0.0, 0.0, 0.0, 1.0)).xyz; 149 | 150 | #if 0 151 | // Conservative cone angle calculation 152 | float a_all = 2.0*atan(0.5*iResolution.y/iCameraF); 153 | float fudge_factor = 1.3; 154 | float a_this = fudge_factor*a_all/(iResolution.y*iScaling); 155 | float sin_alpha_half = sin(a_this/2.0); 156 | float cos_alpha_half = sqrt(1.0 - sin_alpha_half*sin_alpha_half); 157 | #else 158 | // Exact bound cone angle calculation 159 | float cos_alpha_half = dot(rd, normalize(vec3(uv + vec2(0.5, 0.5)*scale, -iCameraF))); 160 | float sin_alpha_half = sqrt(1.0 - cos_alpha_half*cos_alpha_half); 161 | #endif 162 | 163 | rd = normalize((iView * vec4(rd, 0.0)).xyz); 164 | 165 | // Initial step is shared for *all* rays 166 | float t = model(ro); 167 | 168 | int i; 169 | for (i = ZERO; i < STEPS; i++) 170 | { 171 | vec3 p = ro + t*rd; 172 | float d = min(p.y - iGroundHeight, model(p)); 173 | if (d <= sin_alpha_half*t + EPSILON) break; 174 | 175 | #if 0 176 | // Conservative step, results in more iterations but is cheaper to compute 177 | // Note: EPSILON in the termination condition is necessary as this iteration scheme 178 | // converges towards d = sin_alpha_half*t, which causes numerical instability in an 179 | // exact comparison. 180 | t = (t + d)/(1.0 + sin_alpha_half); 181 | #else 182 | // Tight step, results in fewer iterations 183 | // Note: if this is used the EPSILON in the termination condition above is unecessary. 184 | t = t*cos_alpha_half + sqrt(d*d - sin_alpha_half*sin_alpha_half*t*t); 185 | #endif 186 | 187 | if (t > MAX_DISTANCE) break; 188 | } 189 | 190 | fragColor = vec4(t); 191 | } 192 | else 193 | { 194 | vec2 uv = vec2(gl_FragCoord.x, iResolution.y - gl_FragCoord.y) + (noise2f() - vec2(0.5)) - iCameraCenter; 195 | vec3 rd = normalize((iView * vec4(uv, -iCameraF, 0.0)).xyz); 196 | vec3 ro = (iView * vec4(0.0, 0.0, 0.0, 1.0)).xyz; 197 | 198 | float t0 = texelFetch(iChannel0, ivec2(gl_FragCoord.xy*iLowResolution.xy/iResolution.xy), 0).r; 199 | fragColor.rgb = render(ro, rd, t0); 200 | // fragColor.rgb = vec3(t0)/4.0; 201 | fragColor.a = 1.0; 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /libf/compose.f: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | // This shader calculates the mean of accumulated sample images and applies 5 | // gamma correction to the output. 6 | 7 | uniform vec2 iResolution; 8 | uniform sampler2D iChannel0; 9 | uniform int iSamples; 10 | out vec4 fragColor; 11 | 12 | void main() 13 | { 14 | vec2 uv = gl_FragCoord.xy / iResolution.xy; 15 | fragColor = texture(iChannel0, uv) / float(iSamples); 16 | fragColor.rgb = sqrt(fragColor.rgb); 17 | fragColor.a = 1.0; 18 | } 19 | -------------------------------------------------------------------------------- /libf/geometry.f: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | uniform vec2 iResolution; 5 | uniform vec2 iCameraCenter; 6 | uniform float iCameraF; 7 | uniform mat4 iView; 8 | uniform int iDrawMode; 9 | uniform float iMinDistance; 10 | uniform float iMaxDistance; 11 | uniform float iMinThickness; 12 | uniform float iMaxThickness; 13 | uniform sampler1D iColormap; 14 | uniform int iApplyColormap; 15 | out vec4 fragColor; 16 | 17 | #define EPSILON 0.0001 18 | #define STEPS 512 19 | #define MAX_DISTANCE 100.0 20 | 21 | #define DRAW_MODE_NORMALS 0 22 | #define DRAW_MODE_DEPTH 1 23 | #define DRAW_MODE_THICKNESS 2 24 | #define DRAW_MODE_GBUFFER 3 25 | 26 | vec3 rayPinhole(vec2 fragOffset) 27 | { 28 | vec2 uv = vec2(gl_FragCoord.x, iResolution.y - gl_FragCoord.y) + fragOffset - iCameraCenter; 29 | float d = 1.0/length(vec3(uv, iCameraF)); 30 | return vec3(uv*d, -iCameraF*d); 31 | } 32 | 33 | float model(vec3 p); // forward-declaration 34 | 35 | // Adapted from Inigo Quilez 36 | // Source: http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm 37 | vec3 normal(vec3 p) 38 | { 39 | vec3 n = vec3(0.0); 40 | for (int i = ZERO; i < 4; i++) 41 | { 42 | vec3 e = 0.5773*(2.0*vec3((((i+3)>>1)&1),((i>>1)&1),(i&1))-1.0); 43 | n += e*model(p + e*0.002); 44 | } 45 | return normalize(n); 46 | } 47 | 48 | float calcThickness(vec3 ro, vec3 rd) 49 | { 50 | float t = 0.0; 51 | float thickness = 0.0; 52 | for (int i = ZERO; i < STEPS; i++) 53 | { 54 | vec3 p = ro + t*rd; 55 | float d = model(p); 56 | if (d >= -EPSILON) 57 | { 58 | t += max(EPSILON, d); 59 | } 60 | else 61 | { 62 | t += max(EPSILON, -d); 63 | thickness += max(EPSILON, -d); 64 | } 65 | if (t > MAX_DISTANCE) break; 66 | } 67 | return thickness; 68 | } 69 | 70 | float traceModel(vec3 ro, vec3 rd) 71 | { 72 | float t = 0.0; 73 | for (int i = ZERO; i < STEPS; i++) 74 | { 75 | vec3 p = ro + t*rd; 76 | float d = model(p); 77 | if (d <= EPSILON) return t; 78 | t += d; 79 | if (t > MAX_DISTANCE) break; 80 | } 81 | return -1.0; 82 | } 83 | 84 | void main() 85 | { 86 | vec3 rd = rayPinhole(vec2(0.0)); 87 | vec3 ro = (iView * vec4(0.0, 0.0, 0.0, 1.0)).xyz; 88 | rd = normalize((iView * vec4(rd, 0.0)).xyz); 89 | 90 | fragColor = vec4(0.0); 91 | 92 | float t = traceModel(ro, rd); 93 | if (t > 0.0) 94 | { 95 | vec3 p = ro + t*rd; 96 | vec3 n = normal(p); 97 | float thickness = calcThickness(p, rd); 98 | 99 | float t_normalized = (t - iMinDistance) / (iMaxDistance - iMinDistance); 100 | float thickness_normalized = (thickness - iMinThickness) / (iMaxThickness - iMinThickness); 101 | 102 | if (iDrawMode == DRAW_MODE_NORMALS) 103 | { 104 | fragColor.rgb = vec3(0.5) + 0.5*n; 105 | fragColor.a = 1.0; 106 | } 107 | else if (iDrawMode == DRAW_MODE_DEPTH) 108 | { 109 | if (iApplyColormap == 1) fragColor.rgb = texture(iColormap, t_normalized).rgb; 110 | else fragColor.rgb = vec3(t_normalized); 111 | fragColor.a = 1.0; 112 | } 113 | else if (iDrawMode == DRAW_MODE_THICKNESS) 114 | { 115 | if (iApplyColormap == 1) fragColor.rgb = texture(iColormap, thickness_normalized).rgb; 116 | else fragColor.rgb = vec3(thickness_normalized); 117 | fragColor.a = 1.0; 118 | } 119 | else if (iDrawMode == DRAW_MODE_GBUFFER) 120 | { 121 | fragColor.rg = 0.5 + 0.5*n.xy; 122 | fragColor.b = t_normalized; 123 | fragColor.a = thickness; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /libf/hg_sdf.f: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////// 2 | // 3 | // HG_SDF 4 | // 5 | // GLSL LIBRARY FOR BUILDING SIGNED DISTANCE BOUNDS 6 | // 7 | // version 2016-01-10 8 | // 9 | // Check http://mercury.sexy/hg_sdf for updates 10 | // and usage examples. Send feedback to spheretracing@mercury.sexy. 11 | // 12 | // Brought to you by MERCURY http://mercury.sexy 13 | // 14 | // 15 | // 16 | // Released as Creative Commons Attribution-NonCommercial (CC BY-NC) 17 | // 18 | //////////////////////////////////////////////////////////////// 19 | 20 | #define PI 3.14159265359 21 | #define PHI (sqrt(5)*0.5 + 0.5) 22 | 23 | // Clamp to [0,1] - this operation is free under certain circumstances. 24 | // For further information see 25 | // http://www.humus.name/Articles/Persson_LowLevelThinking.pdf and 26 | // http://www.humus.name/Articles/Persson_LowlevelShaderOptimization.pdf 27 | #define saturate(x) clamp(x, 0, 1) 28 | 29 | // Sign function that doesn't return 0 30 | float sgn(float x) { 31 | return (x<0)?-1:1; 32 | } 33 | 34 | vec2 sgn(vec2 v) { 35 | return vec2((v.x<0)?-1:1, (v.y<0)?-1:1); 36 | } 37 | 38 | float square (float x) { 39 | return x*x; 40 | } 41 | 42 | vec2 square (vec2 x) { 43 | return x*x; 44 | } 45 | 46 | vec3 square (vec3 x) { 47 | return x*x; 48 | } 49 | 50 | float lengthSqr(vec3 x) { 51 | return dot(x, x); 52 | } 53 | 54 | 55 | // Maximum/minumum elements of a vector 56 | float vmax(vec2 v) { 57 | return max(v.x, v.y); 58 | } 59 | 60 | float vmax(vec3 v) { 61 | return max(max(v.x, v.y), v.z); 62 | } 63 | 64 | float vmax(vec4 v) { 65 | return max(max(v.x, v.y), max(v.z, v.w)); 66 | } 67 | 68 | float vmin(vec2 v) { 69 | return min(v.x, v.y); 70 | } 71 | 72 | float vmin(vec3 v) { 73 | return min(min(v.x, v.y), v.z); 74 | } 75 | 76 | float vmin(vec4 v) { 77 | return min(min(v.x, v.y), min(v.z, v.w)); 78 | } 79 | 80 | 81 | 82 | 83 | //////////////////////////////////////////////////////////////// 84 | // 85 | // PRIMITIVE DISTANCE FUNCTIONS 86 | // 87 | //////////////////////////////////////////////////////////////// 88 | // 89 | // Conventions: 90 | // 91 | // Everything that is a distance function is called fSomething. 92 | // The first argument is always a point in 2 or 3-space called

. 93 | // Unless otherwise noted, (if the object has an intrinsic "up" 94 | // side or direction) the y axis is "up" and the object is 95 | // centered at the origin. 96 | // 97 | //////////////////////////////////////////////////////////////// 98 | 99 | float fSphere(vec3 p, float r) { 100 | return length(p) - r; 101 | } 102 | 103 | // Plane with normal n (n is normalized) at some distance from the origin 104 | float fPlane(vec3 p, vec3 n, float distanceFromOrigin) { 105 | return dot(p, n) + distanceFromOrigin; 106 | } 107 | 108 | // Cheap Box: distance to corners is overestimated 109 | float fBoxCheap(vec3 p, vec3 b) { //cheap box 110 | return vmax(abs(p) - b); 111 | } 112 | 113 | // Box: correct distance to corners 114 | float fBox(vec3 p, vec3 b) { 115 | vec3 d = abs(p) - b; 116 | return length(max(d, vec3(0))) + vmax(min(d, vec3(0))); 117 | } 118 | 119 | // Same as above, but in two dimensions (an endless box) 120 | float fBox2Cheap(vec2 p, vec2 b) { 121 | return vmax(abs(p)-b); 122 | } 123 | 124 | float fBox2(vec2 p, vec2 b) { 125 | vec2 d = abs(p) - b; 126 | return length(max(d, vec2(0))) + vmax(min(d, vec2(0))); 127 | } 128 | 129 | 130 | // Endless "corner" 131 | float fCorner (vec2 p) { 132 | return length(max(p, vec2(0))) + vmax(min(p, vec2(0))); 133 | } 134 | 135 | // Blobby ball object. You've probably seen it somewhere. This is not a correct distance bound, beware. 136 | float fBlob(vec3 p) { 137 | p = abs(p); 138 | if (p.x < max(p.y, p.z)) p = p.yzx; 139 | if (p.x < max(p.y, p.z)) p = p.yzx; 140 | float b = max(max(max( 141 | dot(p, normalize(vec3(1, 1, 1))), 142 | dot(p.xz, normalize(vec2(PHI+1, 1)))), 143 | dot(p.yx, normalize(vec2(1, PHI)))), 144 | dot(p.xz, normalize(vec2(1, PHI)))); 145 | float l = length(p); 146 | return l - 1.5 - 0.2 * (1.5 / 2)* cos(min(sqrt(1.01 - b / l)*(PI / 0.25), PI)); 147 | } 148 | 149 | // Cylinder standing upright on the xz plane 150 | float fCylinder(vec3 p, float r, float height) { 151 | vec2 d = abs(vec2(length(p.xz),p.y)) - vec2(r, height); 152 | return min(max(d.x,d.y),0.0) + length(max(d,0.0)); 153 | // return d; 154 | } 155 | 156 | // Capsule: A Cylinder with round caps on both sides 157 | float fCapsule(vec3 p, float r, float c) { 158 | return mix(length(p.xz) - r, length(vec3(p.x, abs(p.y) - c, p.z)) - r, step(c, abs(p.y))); 159 | } 160 | 161 | // Distance to line segment between and , used for fCapsule() version 2below 162 | float fLineSegment(vec3 p, vec3 a, vec3 b) { 163 | vec3 ab = b - a; 164 | float t = saturate(dot(p - a, ab) / dot(ab, ab)); 165 | return length((ab*t + a) - p); 166 | } 167 | 168 | // Capsule version 2: between two end points and with radius r 169 | float fCapsule(vec3 p, vec3 a, vec3 b, float r) { 170 | return fLineSegment(p, a, b) - r; 171 | } 172 | 173 | // Torus in the XZ-plane 174 | float fTorus(vec3 p, float smallRadius, float largeRadius) { 175 | return length(vec2(length(p.xz) - largeRadius, p.y)) - smallRadius; 176 | } 177 | 178 | // A circle line. Can also be used to make a torus by subtracting the smaller radius of the torus. 179 | float fCircle(vec3 p, float r) { 180 | float l = length(p.xz) - r; 181 | return length(vec2(p.y, l)); 182 | } 183 | 184 | // A circular disc with no thickness (i.e. a cylinder with no height). 185 | // Subtract some value to make a flat disc with rounded edge. 186 | float fDisc(vec3 p, float r) { 187 | float l = length(p.xz) - r; 188 | return l < 0 ? abs(p.y) : length(vec2(p.y, l)); 189 | } 190 | 191 | // Hexagonal prism, circumcircle variant 192 | float fHexagonCircumcircle(vec3 p, vec2 h) { 193 | vec3 q = abs(p); 194 | return max(q.y - h.y, max(q.x*sqrt(3)*0.5 + q.z*0.5, q.z) - h.x); 195 | //this is mathematically equivalent to this line, but less efficient: 196 | //return max(q.y - h.y, max(dot(vec2(cos(PI/3), sin(PI/3)), q.zx), q.z) - h.x); 197 | } 198 | 199 | // Hexagonal prism, incircle variant 200 | float fHexagonIncircle(vec3 p, vec2 h) { 201 | return fHexagonCircumcircle(p, vec2(h.x*sqrt(3)*0.5, h.y)); 202 | } 203 | 204 | float fTriPrism(vec3 p, float hx, float hy) 205 | { 206 | vec3 q = abs(p); 207 | return max(q.z-hy,max(q.x*0.866025+p.y*0.5,-p.y)-hx*0.5); 208 | } 209 | 210 | // Cone with correct distances to tip and base circle. Y is up, 0 is in the middle of the base. 211 | float fCone(vec3 p, float radius, float height) { 212 | vec2 q = vec2(length(p.xz), p.y); 213 | vec2 tip = q - vec2(0, height); 214 | vec2 mantleDir = normalize(vec2(height, radius)); 215 | float mantle = dot(tip, mantleDir); 216 | float d = max(mantle, -q.y); 217 | float projected = dot(tip, vec2(mantleDir.y, -mantleDir.x)); 218 | 219 | // distance to tip 220 | if ((q.y > height) && (projected < 0)) { 221 | d = max(d, length(tip)); 222 | } 223 | 224 | // distance to base ring 225 | if ((q.x > radius) && (projected > length(vec2(height, radius)))) { 226 | d = max(d, length(q - vec2(radius, 0))); 227 | } 228 | return d; 229 | } 230 | 231 | // 232 | // "Generalized Distance Functions" by Akleman and Chen. 233 | // see the Paper at https://www.viz.tamu.edu/faculty/ergun/research/implicitmodeling/papers/sm99.pdf 234 | // 235 | // This set of constants is used to construct a large variety of geometric primitives. 236 | // Indices are shifted by 1 compared to the paper because we start counting at Zero. 237 | // Some of those are slow whenever a driver decides to not unroll the loop, 238 | // which seems to happen for fIcosahedron und fTruncatedIcosahedron on nvidia 350.12 at least. 239 | // Specialized implementations can well be faster in all cases. 240 | // 241 | 242 | const vec3 GDFVectors[19] = vec3[]( 243 | normalize(vec3(1, 0, 0)), 244 | normalize(vec3(0, 1, 0)), 245 | normalize(vec3(0, 0, 1)), 246 | 247 | normalize(vec3(1, 1, 1 )), 248 | normalize(vec3(-1, 1, 1)), 249 | normalize(vec3(1, -1, 1)), 250 | normalize(vec3(1, 1, -1)), 251 | 252 | normalize(vec3(0, 1, PHI+1)), 253 | normalize(vec3(0, -1, PHI+1)), 254 | normalize(vec3(PHI+1, 0, 1)), 255 | normalize(vec3(-PHI-1, 0, 1)), 256 | normalize(vec3(1, PHI+1, 0)), 257 | normalize(vec3(-1, PHI+1, 0)), 258 | 259 | normalize(vec3(0, PHI, 1)), 260 | normalize(vec3(0, -PHI, 1)), 261 | normalize(vec3(1, 0, PHI)), 262 | normalize(vec3(-1, 0, PHI)), 263 | normalize(vec3(PHI, 1, 0)), 264 | normalize(vec3(-PHI, 1, 0)) 265 | ); 266 | 267 | // Version with variable exponent. 268 | // This is slow and does not produce correct distances, but allows for bulging of objects. 269 | float fGDF(vec3 p, float r, float e, int begin, int end) { 270 | float d = 0; 271 | for (int i = begin; i <= end; ++i) 272 | d += pow(abs(dot(p, GDFVectors[i])), e); 273 | return pow(d, 1/e) - r; 274 | } 275 | 276 | // Version with without exponent, creates objects with sharp edges and flat faces 277 | float fGDF(vec3 p, float r, int begin, int end) { 278 | float d = 0; 279 | for (int i = begin; i <= end; ++i) 280 | d = max(d, abs(dot(p, GDFVectors[i]))); 281 | return d - r; 282 | } 283 | 284 | // Primitives follow: 285 | 286 | float fOctahedron(vec3 p, float r, float e) { 287 | return fGDF(p, r, e, 3, 6); 288 | } 289 | 290 | float fDodecahedron(vec3 p, float r, float e) { 291 | return fGDF(p, r, e, 13, 18); 292 | } 293 | 294 | float fIcosahedron(vec3 p, float r, float e) { 295 | return fGDF(p, r, e, 3, 12); 296 | } 297 | 298 | float fTruncatedOctahedron(vec3 p, float r, float e) { 299 | return fGDF(p, r, e, 0, 6); 300 | } 301 | 302 | float fTruncatedIcosahedron(vec3 p, float r, float e) { 303 | return fGDF(p, r, e, 3, 18); 304 | } 305 | 306 | float fOctahedron(vec3 p, float r) { 307 | return fGDF(p, r, 3, 6); 308 | } 309 | 310 | float fDodecahedron(vec3 p, float r) { 311 | return fGDF(p, r, 13, 18); 312 | } 313 | 314 | float fIcosahedron(vec3 p, float r) { 315 | return fGDF(p, r, 3, 12); 316 | } 317 | 318 | float fTruncatedOctahedron(vec3 p, float r) { 319 | return fGDF(p, r, 0, 6); 320 | } 321 | 322 | float fTruncatedIcosahedron(vec3 p, float r) { 323 | return fGDF(p, r, 3, 18); 324 | } 325 | 326 | // Rotate around a coordinate axis (i.e. in a plane perpendicular to that axis) by angle . 327 | // Read like this: R(p.xz, a) rotates "x towards z". 328 | // This is fast if is a compile-time constant and slower (but still practical) if not. 329 | void pR(inout vec2 p, float a) { 330 | p = cos(a)*p + sin(a)*vec2(p.y, -p.x); 331 | } 332 | 333 | vec2 pOpRotate(in vec2 p, float a) { 334 | return cos(a)*p + sin(a)*vec2(p.y, -p.x); 335 | } 336 | 337 | // Shortcut for 45-degrees rotation 338 | void pR45(inout vec2 p) { 339 | p = (p + vec2(p.y, -p.x))*sqrt(0.5); 340 | } 341 | 342 | // Repeat space along one axis. Use like this to repeat along the x axis: 343 | // - using the return value is optional. 344 | float pMod1(inout float p, float size) { 345 | float halfsize = size*0.5; 346 | float c = floor((p + halfsize)/size); 347 | p = mod(p + halfsize, size) - halfsize; 348 | return c; 349 | } 350 | 351 | // Same, but mirror every second cell so they match at the boundaries 352 | float pModMirror1(inout float p, float size) { 353 | float halfsize = size*0.5; 354 | float c = floor((p + halfsize)/size); 355 | p = mod(p + halfsize,size) - halfsize; 356 | p *= mod(c, 2.0)*2 - 1; 357 | return c; 358 | } 359 | 360 | // Repeat the domain only in positive direction. Everything in the negative half-space is unchanged. 361 | float pModSingle1(inout float p, float size) { 362 | float halfsize = size*0.5; 363 | float c = floor((p + halfsize)/size); 364 | if (p >= 0) 365 | p = mod(p + halfsize, size) - halfsize; 366 | return c; 367 | } 368 | 369 | // Repeat only a few times: from indices to (similar to above, but more flexible) 370 | float pModInterval1(inout float p, float size, float start, float stop) { 371 | float halfsize = size*0.5; 372 | float c = floor((p + halfsize)/size); 373 | p = mod(p+halfsize, size) - halfsize; 374 | if (c > stop) { //yes, this might not be the best thing numerically. 375 | p += size*(c - stop); 376 | c = stop; 377 | } 378 | if (c = (repetitions/2)) c = abs(c); 397 | return c; 398 | } 399 | 400 | // Repeat in two dimensions 401 | vec2 pMod2(inout vec2 p, vec2 size) { 402 | vec2 c = floor((p + size*0.5)/size); 403 | p = mod(p + size*0.5,size) - size*0.5; 404 | return c; 405 | } 406 | 407 | // Same, but mirror every second cell so all boundaries match 408 | vec2 pModMirror2(inout vec2 p, vec2 size) { 409 | vec2 halfsize = size*0.5; 410 | vec2 c = floor((p + halfsize)/size); 411 | p = mod(p + halfsize, size) - halfsize; 412 | p *= mod(c,vec2(2))*2 - vec2(1); 413 | return c; 414 | } 415 | 416 | // Same, but mirror every second cell at the diagonal as well 417 | vec2 pModGrid2(inout vec2 p, vec2 size) { 418 | vec2 c = floor((p + size*0.5)/size); 419 | p = mod(p + size*0.5, size) - size*0.5; 420 | p *= mod(c,vec2(2))*2 - vec2(1); 421 | p -= size/2; 422 | if (p.x > p.y) p.xy = p.yx; 423 | return floor(c/2); 424 | } 425 | 426 | // Repeat in three dimensions 427 | vec3 pMod3(inout vec3 p, vec3 size) { 428 | vec3 c = floor((p + size*0.5)/size); 429 | p = mod(p + size*0.5, size) - size*0.5; 430 | return c; 431 | } 432 | 433 | // Mirror at an axis-aligned plane which is at a specified distance from the origin. 434 | float pMirror (inout float p, float dist) { 435 | float s = sgn(p); 436 | p = abs(p)-dist; 437 | return s; 438 | } 439 | 440 | // Mirror in both dimensions and at the diagonal, yielding one eighth of the space. 441 | // translate by dist before mirroring. 442 | vec2 pMirrorOctant (inout vec2 p, vec2 dist) { 443 | vec2 s = sgn(p); 444 | pMirror(p.x, dist.x); 445 | pMirror(p.y, dist.y); 446 | if (p.y > p.x) 447 | p.xy = p.yx; 448 | return s; 449 | } 450 | 451 | // Reflect space at a plane 452 | float pReflect(inout vec3 p, vec3 planeNormal, float offset) { 453 | float t = dot(p, planeNormal)+offset; 454 | if (t < 0) { 455 | p = p - (2*t)*planeNormal; 456 | } 457 | return sgn(t); 458 | } 459 | 460 | 461 | // The "Chamfer" flavour makes a 45-degree chamfered edge (the diagonal of a square of size ): 462 | float fOpUnionChamfer(float a, float b, float r) { 463 | return min(min(a, b), (a - r + b)*sqrt(0.5)); 464 | } 465 | 466 | // Intersection has to deal with what is normally the inside of the resulting object 467 | // when using union, which we normally don't care about too much. Thus, intersection 468 | // implementations sometimes differ from union implementations. 469 | float fOpIntersectionChamfer(float a, float b, float r) { 470 | return max(max(a, b), (a + r + b)*sqrt(0.5)); 471 | } 472 | 473 | // Difference can be built from Intersection or Union: 474 | float fOpDifferenceChamfer (float a, float b, float r) { 475 | return fOpIntersectionChamfer(a, -b, r); 476 | } 477 | 478 | // The "Round" variant uses a quarter-circle to join the two objects smoothly: 479 | float fOpUnionRound(float a, float b, float r) { 480 | vec2 u = max(vec2(r - a,r - b), vec2(0)); 481 | return max(r, min (a, b)) - length(u); 482 | } 483 | 484 | float fOpIntersectionRound(float a, float b, float r) { 485 | vec2 u = max(vec2(r + a,r + b), vec2(0)); 486 | return min(-r, max (a, b)) + length(u); 487 | } 488 | 489 | float fOpDifferenceRound (float a, float b, float r) { 490 | return fOpIntersectionRound(a, -b, r); 491 | } 492 | 493 | 494 | // The "Columns" flavour makes n-1 circular columns at a 45 degree angle: 495 | float fOpUnionColumns(float a, float b, float r, float n) { 496 | if ((a < r) && (b < r)) { 497 | vec2 p = vec2(a, b); 498 | float columnradius = r*sqrt(2)/((n-1)*2+sqrt(2)); 499 | pR45(p); 500 | p.x -= sqrt(2)/2*r; 501 | p.x += columnradius*sqrt(2); 502 | if (mod(n,2) == 1) { 503 | p.y += columnradius; 504 | } 505 | // At this point, we have turned 45 degrees and moved at a point on the 506 | // diagonal that we want to place the columns on. 507 | // Now, repeat the domain along this direction and place a circle. 508 | pMod1(p.y, columnradius*2); 509 | float result = length(p) - columnradius; 510 | result = min(result, p.x); 511 | result = min(result, a); 512 | return min(result, b); 513 | } else { 514 | return min(a, b); 515 | } 516 | } 517 | 518 | float fOpDifferenceColumns(float a, float b, float r, float n) { 519 | a = -a; 520 | float m = min(a, b); 521 | //avoid the expensive computation where not needed (produces discontinuity though) 522 | if ((a < r) && (b < r)) { 523 | vec2 p = vec2(a, b); 524 | float columnradius = r*sqrt(2)/n/2.0; 525 | columnradius = r*sqrt(2)/((n-1)*2+sqrt(2)); 526 | 527 | pR45(p); 528 | p.y += columnradius; 529 | p.x -= sqrt(2)/2*r; 530 | p.x += -columnradius*sqrt(2)/2; 531 | 532 | if (mod(n,2) == 1) { 533 | p.y += columnradius; 534 | } 535 | pMod1(p.y,columnradius*2); 536 | 537 | float result = -length(p) + columnradius; 538 | result = max(result, p.x); 539 | result = min(result, a); 540 | return -min(result, b); 541 | } else { 542 | return -m; 543 | } 544 | } 545 | 546 | float fOpIntersectionColumns(float a, float b, float r, float n) { 547 | return fOpDifferenceColumns(a,-b,r, n); 548 | } 549 | 550 | // The "Stairs" flavour produces n-1 steps of a staircase: 551 | // much less stupid version by paniq 552 | float fOpUnionStairs(float a, float b, float r, float n) { 553 | float s = r/n; 554 | float u = b-r; 555 | return min(min(a,b), 0.5 * (u + a + abs ((mod (u - a + s, 2 * s)) - s))); 556 | } 557 | 558 | // We can just call Union since stairs are symmetric. 559 | float fOpIntersectionStairs(float a, float b, float r, float n) { 560 | return -fOpUnionStairs(-a, -b, r, n); 561 | } 562 | 563 | float fOpDifferenceStairs(float a, float b, float r, float n) { 564 | return -fOpUnionStairs(-a, b, r, n); 565 | } 566 | 567 | 568 | // Similar to fOpUnionRound, but more lipschitz-y at acute angles 569 | // (and less so at 90 degrees). Useful when fudging around too much 570 | // by MediaMolecule, from Alex Evans' siggraph slides 571 | float fOpUnionSoft(float a, float b, float r) { 572 | float e = max(r - abs(a - b), 0); 573 | return min(a, b) - e*e*0.25/r; 574 | } 575 | 576 | 577 | // produces a cylindical pipe that runs along the intersection. 578 | // No objects remain, only the pipe. This is not a boolean operator. 579 | float fOpPipe(float a, float b, float r) { 580 | return length(vec2(a, b)) - r; 581 | } 582 | 583 | // first object gets a v-shaped engraving where it intersect the second 584 | float fOpEngrave(float a, float b, float r) { 585 | return max(a, (a + r - abs(b))*sqrt(0.5)); 586 | } 587 | 588 | // first object gets a capenter-style groove cut out 589 | float fOpGroove(float a, float b, float ra, float rb) { 590 | return max(a, min(a + ra, rb - abs(b))); 591 | } 592 | 593 | // first object gets a capenter-style tongue attached 594 | float fOpTongue(float a, float b, float ra, float rb) { 595 | return min(a, max(a - ra, abs(b) - rb)); 596 | } 597 | 598 | float fPrism(vec3 p, vec3 b, float angle) 599 | { 600 | vec3 q = p; 601 | q.x = abs(q.x); 602 | pR(q.xy, angle); 603 | return max(fBox(q, b), fBox(p - vec3(0,0.1,0), b)); 604 | } 605 | -------------------------------------------------------------------------------- /libf/publication.f: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | uniform vec2 iResolution; 5 | uniform int iFrame; 6 | uniform vec2 iCameraCenter; 7 | uniform float iCameraF; 8 | uniform mat4 iView; 9 | uniform int iSamples; 10 | uniform vec3 iToSun; 11 | uniform vec3 iSunStrength; 12 | uniform float iCosSunSize; 13 | uniform int iDrawIsolines; 14 | uniform vec3 iIsolineColor; 15 | uniform float iIsolineThickness; 16 | uniform float iIsolineSpacing; 17 | uniform float iIsolineMax; 18 | uniform int iMaterialGlossy; 19 | uniform float iMaterialSpecularExponent; 20 | uniform vec3 iMaterialSpecularAlbedo; 21 | uniform vec3 iMaterialAlbedo; 22 | uniform int iGroundReflective; 23 | uniform float iGroundHeight; 24 | uniform float iGroundSpecularExponent; 25 | uniform float iGroundReflectivity; 26 | out vec4 fragColor; 27 | 28 | #define EPSILON 0.0007 29 | #define STEPS 512 30 | #define M_PI 3.1415926535897932384626433832795 31 | #define MAX_DISTANCE 100.0 32 | #define MAX_DISTANCE_VISIBILITY_TEST 10.0 33 | 34 | float model(vec3 p); // forward declaration 35 | 36 | // Adapted from: lumina.sourceforge.net/Tutorials/Noise.html 37 | vec2 seed = vec2(-1,1)*(iSamples*(1.0/12.0) + 1.0); 38 | vec2 noise2f() 39 | { 40 | seed += vec2(-1, 1); 41 | return vec2(fract(sin(dot(seed.xy, vec2(12.9898, 78.233))) * 43758.5453), 42 | fract(cos(dot(seed.xy, vec2(4.898, 7.23))) * 23421.631)); 43 | } 44 | 45 | vec3 rayPinhole(vec2 fragOffset) 46 | { 47 | vec2 uv = vec2(gl_FragCoord.x, iResolution.y - gl_FragCoord.y) + fragOffset - iCameraCenter; 48 | float d = 1.0/length(vec3(uv, iCameraF)); 49 | return vec3(uv*d, -iCameraF*d); 50 | } 51 | 52 | // Adapted from Inigo Quilez 53 | // Source: http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm 54 | vec3 normal(vec3 p) 55 | { 56 | vec3 n = vec3(0.0); 57 | for (int i = ZERO; i < 4; i++) 58 | { 59 | vec3 e = 0.5773*(2.0*vec3((((i+3)>>1)&1),((i>>1)&1),(i&1))-1.0); 60 | n += e*model(p + e*0.002); 61 | } 62 | return normalize(n); 63 | } 64 | 65 | float traceGround(vec3 ro, vec3 rd) 66 | { 67 | if (rd.y == 0.0) return -1.0; 68 | else return (iGroundHeight - ro.y)/rd.y; 69 | } 70 | 71 | float traceModel(vec3 ro, vec3 rd) 72 | { 73 | float t = 0.0; 74 | for (int i = ZERO; i < STEPS; i++) 75 | { 76 | vec3 p = ro + t*rd; 77 | float d = model(p); 78 | if (d <= EPSILON) return t; 79 | t += d; 80 | if (t > MAX_DISTANCE) break; 81 | } 82 | return -1.0; 83 | } 84 | 85 | bool isVisible(vec3 ro, vec3 rd) 86 | { 87 | float tGround = traceGround(ro, rd); 88 | if (tGround > EPSILON) 89 | return false; 90 | float t = 0.0; 91 | for (int i = ZERO; i < STEPS; i++) 92 | { 93 | float d = model(ro + t*rd); 94 | t += d; 95 | if (d <= EPSILON) 96 | return false; 97 | if (t > MAX_DISTANCE_VISIBILITY_TEST) 98 | break; 99 | } 100 | return true; 101 | } 102 | 103 | vec3 cosineWeightedSample(vec3 normal) 104 | { 105 | vec2 u = noise2f(); 106 | float a = 0.99*(1.0 - 2.0*u[0]); 107 | float b = 0.99*(sqrt(1.0 - a*a)); 108 | float phi = 6.2831853072*u[1]; 109 | float x = normal.x + b*cos(phi); 110 | float y = normal.y + b*sin(phi); 111 | float z = normal.z + a; 112 | return normalize(vec3(x,y,z)); 113 | } 114 | 115 | // The corresponding direction pdf is: (exponent + 2)/2pi pow(cosAlpha, exponent) 116 | vec3 phongWeightedSample(vec3 dir, float exponent) 117 | { 118 | vec3 tangent = vec3(1.0, 0.0, 0.0); 119 | if (abs(tangent.x) > 0.9) 120 | tangent = vec3(0.0, 1.0, 0.0); 121 | vec3 bitangent = cross(tangent, dir); 122 | tangent = cross(dir, bitangent); 123 | vec2 u = noise2f(); 124 | float cosAlpha = pow(u[0], 1.0/(exponent + 1.0)); 125 | float sinAlpha = sqrt(1.0 - cosAlpha*cosAlpha); 126 | float phi = 2.0*M_PI*u[1]; 127 | float x = sinAlpha*cos(phi); 128 | float y = cosAlpha; 129 | float z = sinAlpha*sin(phi); 130 | return x*tangent + y*dir + z*bitangent; 131 | } 132 | 133 | vec3 colorModel(vec3 p, vec3 ro) 134 | { 135 | vec3 n = normal(p); 136 | vec3 v = normalize(p - ro); // from eye to point 137 | ro = p + n*2.0*EPSILON; 138 | 139 | vec3 result = vec3(0.0); 140 | 141 | vec3 rd = cosineWeightedSample(n); 142 | if (isVisible(ro,rd)) 143 | result += vec3(1.0); 144 | 145 | rd = iToSun; 146 | if (isVisible(ro,rd)) 147 | result += vec3(1.0)*max(0.0,dot(n, rd)); 148 | 149 | result *= iMaterialAlbedo; 150 | 151 | if (iMaterialGlossy == 1) 152 | { 153 | vec3 w_s = v - 2.0*dot(n, v)*n; 154 | rd = phongWeightedSample(w_s, iMaterialSpecularExponent); 155 | if (isVisible(ro, rd) && dot(rd, iToSun) >= iCosSunSize) 156 | result += iMaterialSpecularAlbedo; 157 | } 158 | return result; 159 | } 160 | 161 | // Computes a color alternating between white and gray where the gray lines 162 | // indicate points of identical distance to the model. 163 | vec3 colorIsolines(vec3 p) 164 | { 165 | float d = model(p); 166 | float a = mod(d - iIsolineThickness*0.5, iIsolineSpacing); 167 | float t = step(iIsolineSpacing-iIsolineThickness, a) * (1.0 - step(iIsolineMax, d)); 168 | return mix(vec3(1.0), iIsolineColor, t); 169 | } 170 | 171 | vec3 colorGround(vec3 p, vec3 ro) 172 | { 173 | vec3 albedo = vec3(1.0); 174 | if (iDrawIsolines==1) 175 | albedo = colorIsolines(p); 176 | 177 | vec3 n = vec3(0.0, 1.0, 0.0); 178 | vec3 v = normalize(p - ro); 179 | ro = p + n*2.0*EPSILON; 180 | 181 | vec3 result = vec3(0.0); 182 | 183 | vec3 rd = cosineWeightedSample(n); 184 | if (isVisible(ro,rd)) 185 | result += vec3(1.0); 186 | 187 | rd = iToSun; 188 | if (isVisible(ro,rd)) 189 | result += vec3(1.0)*max(0.0,dot(n, rd)); 190 | 191 | if (iGroundReflective == 1) 192 | { 193 | vec3 w_s = v - 2.0*dot(n, v)*n; 194 | rd = phongWeightedSample(w_s, iGroundSpecularExponent); 195 | float tModel = traceModel(ro, rd); 196 | if (tModel > 0.0) 197 | result = mix(result, colorModel(ro + tModel*rd, ro), iGroundReflectivity); 198 | } 199 | 200 | return result*albedo; 201 | } 202 | 203 | void main() 204 | { 205 | vec3 rd = rayPinhole(2.0*(noise2f() - vec2(0.5))); 206 | vec3 ro = (iView * vec4(0.0, 0.0, 0.0, 1.0)).xyz; 207 | rd = normalize((iView * vec4(rd, 0.0)).xyz); 208 | 209 | fragColor.rgb = vec3(1.0); 210 | float tModel = traceModel(ro, rd); 211 | float tGround = traceGround(ro, rd); 212 | if (tGround > 0.0 && ((tModel > 0.0 && tGround < tModel) || tModel < 0.0)) 213 | fragColor.rgb = colorGround(ro + rd*tGround, ro); 214 | else if (tModel > 0.0 && ((tGround > 0.0 && tModel < tGround) || tGround < 0.0)) 215 | fragColor.rgb = colorModel(ro + rd*tModel, ro); 216 | fragColor.a = 1.0; 217 | } 218 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | # Python bindings for the fraktal core library 2 | 3 | ## Installation 4 | 5 | * Run the appropriate build script to generate a dynamic library for your platform. On Windows/MSVC this is done using build_dynamic_lib. On Linux/MacOS this is done using the Makefile. 6 | 7 | * Copy the pyfraktal directory into your project or Python installation. 8 | 9 | * Make the dynamic library accessible to Python. You can do this by defining an environment variable "PYFRAKTAL_DLL" to be the complete path to the fraktal.dll (or .so) on your system. You may also copy the library into your project or the pyfraktal package directory. 10 | 11 | ## Test your installation 12 | 13 | You can test your installation by running the following in Python: 14 | 15 | ``` 16 | import fraktal 17 | a = fraktal.create_array(None, 32, 16, 4, fraktal.FLOAT, fraktal.READ_ONLY) 18 | w,h = fraktal.array_size(a) 19 | print(w, h) 20 | ``` 21 | 22 | If fraktal is successfully installed, the script should print "(32, 16)".. 23 | 24 | -------------------------------------------------------------------------------- /python/fraktal/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Python bindings for fraktal. 3 | """ 4 | 5 | __author__ = 'Simen Haugo' 6 | __license__ = 'MIT' 7 | 8 | import sys 9 | import os 10 | import ctypes 11 | 12 | _to_char_p = lambda s: s.encode('utf-8') 13 | 14 | libname = 'fraktal.so' 15 | if sys.platform == 'win32': 16 | libname = 'fraktal.dll' 17 | 18 | if os.environ.get('PYFRAKTAL_DLL', ''): 19 | try: 20 | _fraktal = ctypes.CDLL(os.environ['PYFRAKTAL_DLL']) 21 | except OSError: 22 | _fraktal = None 23 | else: 24 | try: 25 | _fraktal = ctypes.CDLL(libname) 26 | except OSError: 27 | # try the package directory 28 | try: 29 | _fraktal = ctypes.CDLL(os.path.join(os.path.abspath(os.path.dirname(__file__)), libname)) 30 | except OSError: 31 | _fraktal = None 32 | 33 | if _fraktal is None: 34 | raise ImportError( 35 | "Failed to load fraktal dynamic/shared library. " 36 | "Ensure that fraktal.dll (or .so) is accessible " 37 | "from the working directory. You may alternatively " 38 | "set the environment variable PYFRAKTAL_DLL to be " 39 | "the full path to fraktal.dll/so on your computer.") 40 | 41 | ############################################################ 42 | # §1 Enums 43 | ############################################################ 44 | 45 | READ_ONLY = 0 46 | READ_WRITE = 1 47 | FLOAT = 2 48 | UINT8 = 3 49 | CLAMP_TO_EDGE = 4 50 | REPEAT = 5 51 | LINEAR = 6 52 | NEAREST = 7 53 | 54 | class FraktalError(Exception): 55 | def __init__(self, message): 56 | super(FraktalError, self).__init__(message) 57 | 58 | ############################################################ 59 | # §2 Arrays 60 | ############################################################ 61 | 62 | _fraktal.fraktal_create_array.restype = ctypes.c_void_p 63 | _fraktal.fraktal_create_array.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int] 64 | def create_array(data, width, height, channels, format, access): 65 | if data is None: 66 | return _fraktal.fraktal_create_array(None, width, height, channels, format, access) 67 | else: 68 | if format == FLOAT: 69 | pdata = (ctypes.c_float*(channels*width*height))(*data) 70 | elif format == UINT8: 71 | pdata = (ctypes.c_ubyte*(channels*width*height))(*data) 72 | else: 73 | raise 74 | return _fraktal.fraktal_create_array(pdata, width, height, channels, format, access) 75 | 76 | _fraktal.fraktal_destroy_array.restype = None 77 | _fraktal.fraktal_destroy_array.argtypes = [ctypes.c_void_p] 78 | def destroy_array(array): 79 | _fraktal.fraktal_destroy_array(array) 80 | 81 | _fraktal.fraktal_zero_array.restype = None 82 | _fraktal.fraktal_zero_array.argtypes = [ctypes.c_void_p] 83 | def zero_array(array): 84 | _fraktal.fraktal_zero_array(array) 85 | 86 | _fraktal.fraktal_to_cpu.restype = None 87 | _fraktal.fraktal_to_cpu.argtypes = [ctypes.c_void_p, ctypes.c_void_p] 88 | def to_cpu(array): 89 | width,height = array_size(array) 90 | channels = array_channels(array) 91 | format = array_format(array) 92 | if format == FLOAT: 93 | array_type = ctypes.c_float * (channels * width * height) 94 | dcpu = array_type() 95 | _fraktal.fraktal_to_cpu(dcpu, array) 96 | return [float(i) for i in dcpu] 97 | elif format == UINT8: 98 | array_type = ctypes.c_ubyte * (channels * width * height) 99 | dcpu = array_type() 100 | _fraktal.fraktal_to_cpu(dcpu, array) 101 | return [int(i) for i in dcpu] 102 | else: 103 | raise 104 | 105 | _fraktal.fraktal_array_size.restype = None 106 | _fraktal.fraktal_array_size.argtypes = [ctypes.c_void_p, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)] 107 | def array_size(array): 108 | width = ctypes.c_int(0) 109 | pwidth = ctypes.pointer(width) 110 | height = ctypes.c_int(0) 111 | pheight = ctypes.pointer(height) 112 | _fraktal.fraktal_array_size(array, pwidth, pheight) 113 | return width.value, height.value 114 | 115 | _fraktal.fraktal_array_channels.restype = ctypes.c_int 116 | _fraktal.fraktal_array_channels.argtypes = [ctypes.c_void_p] 117 | def array_format(array): 118 | return _fraktal.fraktal_array_format(array) 119 | 120 | _fraktal.fraktal_array_channels.restype = ctypes.c_int 121 | _fraktal.fraktal_array_channels.argtypes = [ctypes.c_void_p] 122 | def array_channels(array): 123 | return _fraktal.fraktal_array_channels(array) 124 | 125 | ############################################################ 126 | # §3 Kernels 127 | ############################################################ 128 | 129 | _fraktal.fraktal_create_link.restype = ctypes.c_void_p 130 | _fraktal.fraktal_create_link.argtypes = [] 131 | def create_link(): 132 | return _fraktal.fraktal_create_link() 133 | 134 | _fraktal.fraktal_destroy_link.restype = None 135 | _fraktal.fraktal_destroy_link.argtypes = [ctypes.c_void_p] 136 | def destroy_link(link): 137 | return _fraktal.fraktal_destroy_link(link) 138 | 139 | _fraktal.fraktal_add_link_data.restype = None 140 | _fraktal.fraktal_add_link_data.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_size_t, ctypes.c_char_p] 141 | def add_link_data(link, data, size, name): 142 | return _fraktal.fraktal_add_link_data(link, data, size, _to_char_p(name)) 143 | 144 | _fraktal.fraktal_add_link_file.restype = None 145 | _fraktal.fraktal_add_link_file.argtypes = [ctypes.c_void_p, ctypes.c_char_p] 146 | def add_link_file(link, path): 147 | return _fraktal.fraktal_add_link_file(link, _to_char_p(path)) 148 | 149 | _fraktal.fraktal_destroy_kernel.restype = None 150 | _fraktal.fraktal_destroy_kernel.argtypes = [ctypes.c_void_p] 151 | def destroy_kernel(kernel): 152 | return _fraktal.fraktal_destroy_kernel(kernel) 153 | 154 | _fraktal.fraktal_load_kernel.restype = ctypes.c_void_p 155 | _fraktal.fraktal_load_kernel.argtypes = [ctypes.c_char_p] 156 | def load_kernel(filename): 157 | return _fraktal.fraktal_load_kernel(_to_char_p(filename)) 158 | 159 | _fraktal.fraktal_use_kernel.restype = None 160 | _fraktal.fraktal_use_kernel.argtypes = [ctypes.c_void_p] 161 | def use_kernel(kernel): 162 | _fraktal.fraktal_use_kernel(kernel) 163 | 164 | _fraktal.fraktal_run_kernel.restype = None 165 | _fraktal.fraktal_run_kernel.argtypes = [ctypes.c_void_p] 166 | def run_kernel(array): 167 | _fraktal.fraktal_run_kernel(array) 168 | 169 | ############################################################ 170 | # §4 Parameters 171 | ############################################################ 172 | 173 | _fraktal.fraktal_get_param_offset.restype = ctypes.c_int 174 | _fraktal.fraktal_get_param_offset.argtypes = [ctypes.c_void_p, ctypes.c_char_p] 175 | def get_param_offset(kernel, name): 176 | return _fraktal.fraktal_get_param_offset(kernel, _to_char_p(name)) 177 | 178 | _fraktal.fraktal_param_1f.restype = None 179 | _fraktal.fraktal_param_1f.argtypes = [ctypes.c_int, ctypes.c_float] 180 | def fraktal_param_1f(offset, x): 181 | _fraktal.fraktal_param_1f(offset, x) 182 | 183 | _fraktal.fraktal_param_2f.restype = None 184 | _fraktal.fraktal_param_2f.argtypes = [ctypes.c_int, ctypes.c_float, ctypes.c_float] 185 | def fraktal_param_2f(offset, x, y): 186 | _fraktal.fraktal_param_2f(offset, x, y) 187 | 188 | _fraktal.fraktal_param_3f.restype = None 189 | _fraktal.fraktal_param_3f.argtypes = [ctypes.c_int, ctypes.c_float, ctypes.c_float, ctypes.c_float] 190 | def fraktal_param_3f(offset, x, y, z): 191 | _fraktal.fraktal_param_3f(offset, x, y, z) 192 | 193 | _fraktal.fraktal_param_4f.restype = None 194 | _fraktal.fraktal_param_4f.argtypes = [ctypes.c_int, ctypes.c_float, ctypes.c_float, ctypes.c_float, ctypes.c_float] 195 | def fraktal_param_4f(offset, x, y, z, w): 196 | _fraktal.fraktal_param_4f(offset, x, y, z, w) 197 | 198 | _fraktal.fraktal_param_1i.restype = None 199 | _fraktal.fraktal_param_1i.argtypes = [ctypes.c_int, ctypes.c_int] 200 | def fraktal_param_1i(offset, x): 201 | _fraktal.fraktal_param_1i(offset, x) 202 | 203 | _fraktal.fraktal_param_2i.restype = None 204 | _fraktal.fraktal_param_2i.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int] 205 | def fraktal_param_2i(offset, x, y): 206 | _fraktal.fraktal_param_2i(offset, x, y) 207 | 208 | _fraktal.fraktal_param_3i.restype = None 209 | _fraktal.fraktal_param_3i.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int] 210 | def fraktal_param_3i(offset, x, y, z): 211 | _fraktal.fraktal_param_3i(offset, x, y, z) 212 | 213 | _fraktal.fraktal_param_4i.restype = None 214 | _fraktal.fraktal_param_4i.argtypes = [ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int, ctypes.c_int] 215 | def fraktal_param_4i(offset, x, y, z, w): 216 | _fraktal.fraktal_param_4i(offset, x, y, z, w) 217 | 218 | _fraktal.fraktal_param_matrix4f.restype = None 219 | _fraktal.fraktal_param_matrix4f.argtypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_float)] 220 | def param_matrix4f(offset, data, transpose=False): 221 | data_type = ctypes.c_float * (4 * 4) 222 | pdata = data_type() 223 | if transpose: 224 | for col in range(4): 225 | for row in range(4): 226 | pdata[row + 4*col] = data[row][col] 227 | else: 228 | for col in range(4): 229 | for row in range(4): 230 | pdata[col + 4*row] = data[row][col] 231 | _fraktal.fraktal_param_matrix4f(offset, pdata) 232 | 233 | _fraktal.fraktal_param_array.restype = None 234 | _fraktal.fraktal_param_array.argtypes = [ctypes.c_int, ctypes.c_void_p] 235 | def param_array(offset, array): 236 | return _fraktal.fraktal_param_array(offset, array) 237 | 238 | 239 | ############################################################ 240 | # §5 Context management 241 | ############################################################ 242 | 243 | _fraktal.fraktal_create_context.restype = None 244 | _fraktal.fraktal_create_context.argtypes = [] 245 | def create_context(): 246 | _fraktal.fraktal_create_context() 247 | 248 | _fraktal.fraktal_destroy_context.restype = None 249 | _fraktal.fraktal_destroy_context.argtypes = [] 250 | def destroy_context(): 251 | _fraktal.fraktal_destroy_context() 252 | 253 | _fraktal.fraktal_push_current_context.restype = None 254 | _fraktal.fraktal_push_current_context.argtypes = [] 255 | def push_current_context(): 256 | _fraktal.fraktal_push_current_context() 257 | 258 | _fraktal.fraktal_pop_current_context.restype = None 259 | _fraktal.fraktal_pop_current_context.argtypes = [] 260 | def pop_current_context(): 261 | _fraktal.fraktal_pop_current_context() 262 | -------------------------------------------------------------------------------- /res/fraktal-logo-source.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 20 | 40 | 49 | 50 | 52 | 53 | 55 | image/svg+xml 56 | 58 | 59 | 60 | 61 | 62 | 68 | 75 | 76 | 80 | 81 | -------------------------------------------------------------------------------- /res/fraktal-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /res/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightbits/fraktal/b8760dc2db979efb91a7b001086b873dfaa22242/res/icon.ico -------------------------------------------------------------------------------- /res/resources.rc: -------------------------------------------------------------------------------- 1 | GLFW_ICON ICON "icon.ico" 2 | -------------------------------------------------------------------------------- /src/fraktal.cpp: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | /* 5 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 | FRAKTAL CORE LIBRARY 7 | COMPILATION MANUAL 8 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 9 | This file defines the implementation for the core fraktal library. You can 10 | compile this file to a .dll or .lib or #include "fraktal.cpp" directly in 11 | main if you're a fan of unity builds. 12 | 13 | 'build.bat' and 'Makefile' in the root show an example of how to build the 14 | fraktal core library and how to link against it. 15 | 16 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 17 | § Compilation flags 18 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 19 | fraktal can be compiled with several optional flags to enable or disable 20 | certain behaviors. You can provide these to your compiler in your build, 21 | or #define them directly if you do a unity build. 22 | 23 | -D FRAKTAL_OMIT_GL_SYMBOLS -> prevents definition of OpenGL symbols 24 | (useful for unity-builds) 25 | -D fraktal_assert -> bring your own assert macro 26 | 27 | */ 28 | 29 | #include "fraktal.h" 30 | 31 | #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) 32 | #define _CRT_SECURE_NO_WARNINGS 33 | #endif 34 | 35 | #ifndef fraktal_assert 36 | #include 37 | #define fraktal_assert assert 38 | #endif 39 | 40 | #ifndef FRAKTAL_OMIT_GL_SYMBOLS 41 | #include 42 | #include 43 | #endif 44 | 45 | #define fraktal_check_gl_error() fraktal_assert(glGetError() == GL_NO_ERROR) 46 | 47 | #include "fraktal_types.h" 48 | #include "fraktal_context.h" 49 | #include "fraktal_array.h" 50 | #include "fraktal_kernel.h" 51 | #include "fraktal_parse.h" 52 | #include "fraktal_link.h" 53 | -------------------------------------------------------------------------------- /src/fraktal.h: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | /* 5 | 6 | Index of this file: 7 | (A decent code editor should let you jump quickly to a section or function) 8 | 9 | §1 Types and forward declarations 10 | ....fEnum 11 | §2 Arrays 12 | ....fraktal_create_array 13 | ....fraktal_destroy_array 14 | ....fraktal_zero_array 15 | ....fraktal_to_cpu 16 | ....fraktal_array_format 17 | ....fraktal_array_size 18 | ....fraktal_array_channels 19 | ....fraktal_is_valid_array 20 | ....fraktal_get_gl_handle 21 | §3 Kernels 22 | ....fraktal_create_link 23 | ....fraktal_destroy_link 24 | ....fraktal_add_link_data 25 | ....fraktal_link_kernel 26 | ....fraktal_destroy_kernel 27 | ....fraktal_load_kernel 28 | ....fraktal_use_kernel 29 | ....fraktal_run_kernel 30 | §4 Parameters 31 | ....fraktal_get_param_offset 32 | ....fraktal_param_... 33 | §5 Context management 34 | ....fraktal_create_context 35 | ....fraktal_destroy_context 36 | ....fraktal_push_current_context 37 | ....fraktal_pop_current_context 38 | */ 39 | 40 | #pragma once 41 | 42 | #ifdef __cplusplus 43 | extern "C" { 44 | #endif 45 | 46 | // FRAKTALAPI is used to declare functions as visible when 47 | // linking against a DLL / shared library / dynamic library. 48 | #if defined(_WIN32) && defined(FRAKTAL_BUILD_DLL) 49 | // We are building fraktal as a Win32 DLL 50 | #define FRAKTALAPI __declspec(dllexport) 51 | #elif defined(__GNUC__) && defined(FRAKTAL_BUILD_DLL) 52 | // We are building fraktal as a shared / dynamic library 53 | #define FRAKTALAPI __attribute__((visibility("default"))) 54 | #else 55 | // We are building or calling fraktal as a static library 56 | #define FRAKTALAPI 57 | #endif 58 | 59 | //----------------------------------------------------------------------------- 60 | // §1 Types and forward declarations 61 | //----------------------------------------------------------------------------- 62 | 63 | typedef int fEnum; 64 | enum fEnum_ 65 | { 66 | // Array access modes 67 | FRAKTAL_READ_ONLY, 68 | FRAKTAL_READ_WRITE, 69 | 70 | // Array formats 71 | FRAKTAL_FLOAT, 72 | FRAKTAL_UINT8, 73 | 74 | // Texture wrap modes 75 | FRAKTAL_CLAMP_TO_EDGE, 76 | FRAKTAL_REPEAT, 77 | 78 | // Texture filter modes 79 | FRAKTAL_LINEAR, 80 | FRAKTAL_NEAREST, 81 | }; 82 | 83 | struct fArray; 84 | struct fKernel; 85 | struct fLinkState; 86 | 87 | //----------------------------------------------------------------------------- 88 | // §2 Arrays 89 | //----------------------------------------------------------------------------- 90 | 91 | /* 92 | Creates a 1D or 2D GPU array of packed float or uint8 vector values 93 | of the specified dimensions. 94 | 95 | 'data' : An optional pointer to a region in CPU memory used 96 | to initialize the array. The CPU memory must be a 97 | contiguous array of packed float or uint8 vector 98 | values matching the given channels and dimensions. 99 | 'channels': The number of vector components. Must be 1, 2 or 4. 100 | 'width' : The number of array values along x. 101 | 'height' : The number of array values along y. If 1, the array 102 | is a 1D array, otherwise the array is a 2D array. 103 | 'depth' : The number of array values along z. If width, height 104 | and depth are all > 1 the array is a 3D array. 105 | 'format' : Must be FRAKTAL_FLOAT or FRAKTAL_UINT8. 106 | 'access' : Must be FRAKTAL_READ_ONLY or FRAKTAL_READ_WRITE. 107 | 108 | If successful, the function returns a handle to a GPU array that 109 | can be used as kernel input or an output target (if 'access' is 110 | not FRAKTAL_READ_ONLY). 111 | 112 | If the 'data' is NULL, the values of the array are uninitialized 113 | and undefined. The array may be cleared using fraktal_zero_array. 114 | */ 115 | FRAKTALAPI fArray *fraktal_create_array( 116 | const void *data, 117 | int channels, 118 | int width, 119 | int height, 120 | int depth, 121 | fEnum format, 122 | fEnum access); 123 | 124 | /* 125 | Frees all memory associated with an array. 126 | 127 | If 'a' is NULL the function silently returns. 128 | */ 129 | FRAKTALAPI void fraktal_destroy_array(fArray *a); 130 | 131 | /* 132 | Sets each value in the array to 0. If 'a' has multiple channels, 133 | each channel is set to the value 0. 134 | 135 | Passing an invalid array or NULL will trigger an assertion. 136 | */ 137 | FRAKTALAPI void fraktal_zero_array(fArray *a); 138 | 139 | /* 140 | Copies the values of a GPU array to a region of memory allocated 141 | on the CPU. The destination must be of the same size in bytes as 142 | the GPU array. 143 | 144 | 'cpu_memory' must not be NULL and 'a' must be a valid array. 145 | */ 146 | FRAKTALAPI void fraktal_to_cpu(void *cpu_memory, fArray *a); 147 | 148 | /* 149 | These methods return information about an array. 150 | */ 151 | FRAKTALAPI void fraktal_array_size(fArray *a, int *width, int *height, int *depth); 152 | FRAKTALAPI fEnum fraktal_array_format(fArray *a); // -1 if 'a' is NULL 153 | FRAKTALAPI int fraktal_array_channels(fArray *a); // 0 is 'a' is NULL 154 | 155 | /* 156 | Returns true if the fArray satisfies the following properties: 157 | * Width is > 0 158 | * Height is > 0 (1 means 'a' is a 1D array) 159 | * Channels is 1, 2 or 4 160 | * Access mode is among the modes listed in fEnum. 161 | * Format is among the formats listed in fEnum. 162 | */ 163 | FRAKTALAPI bool fraktal_is_valid_array(fArray *a); 164 | 165 | /* 166 | If the backend uses OpenGL 3.1, the result is a GLuint handle to 167 | the array's underlying Texture Object, which can be passed to 168 | glBindTexture. The texture target is either GL_TEXTURE_1D, if 169 | 'a' is a 1D array, or GL_TEXTURE_2D, if 'a' is a 2D array. 170 | */ 171 | FRAKTALAPI unsigned int fraktal_get_gl_handle(fArray *a); 172 | 173 | //----------------------------------------------------------------------------- 174 | // §3 Kernels 175 | //----------------------------------------------------------------------------- 176 | 177 | /* 178 | On success, the function returns a handle that should be passed 179 | to subsequent link_add_file or add_link_data calls. If the call 180 | is successful, the caller owns the returned fLinkState, which 181 | should eventually be destroyed with fraktal_destroy_link. 182 | */ 183 | FRAKTALAPI fLinkState *fraktal_create_link(); 184 | 185 | /* 186 | Frees memory associated with a linking operation. On return, the 187 | fLinkState handle is invalidated and should not be used anywhere. 188 | 189 | If 'link' is NULL the function silently returns. 190 | */ 191 | FRAKTALAPI void fraktal_destroy_link(fLinkState *link); 192 | 193 | /* 194 | 'link': Obtained from fraktal_create_link. 195 | 'data': A pointer to a buffer containing kernel source. Must 196 | be NULL-terminated. 197 | 'size': Length of input data in bytes (excluding NULL-terminator). 198 | 0 can be passed if the input is a NULL-terminated string. 199 | 'name': An optional name for this input in log messages. 200 | 201 | No references are kept to 'data' (it can safely be freed afterward). 202 | */ 203 | FRAKTALAPI bool fraktal_add_link_data( 204 | fLinkState *link, 205 | const char *data, 206 | unsigned int size, 207 | const char *name); 208 | 209 | /* 210 | 'link': Obtained from fraktal_create_link. 211 | 'path': A NULL-terminated path to a file containing kernel source. 212 | 213 | This method is equivalent to calling add_link_data on the contents 214 | of the file. 215 | */ 216 | FRAKTALAPI bool fraktal_add_link_file(fLinkState *link, const char *path); 217 | 218 | /* 219 | On success, the method returns a fKernel handle required in all 220 | kernel-specific operations, such as execution, setting parameters, 221 | or obtaining information on active parameters. 222 | 223 | If the call is successful, the caller owns the returned fKernel, 224 | which should eventually be destroyed with fraktal_destroy_kernel. 225 | */ 226 | FRAKTALAPI fKernel *fraktal_link_kernel(fLinkState *link); 227 | 228 | /* 229 | Frees memory associated with a kernel. On return, the fKernel handle 230 | is invalidated and should not be used anywhere. 231 | 232 | If NULL is passed the method silently returns. 233 | */ 234 | FRAKTALAPI void fraktal_destroy_kernel(fKernel *f); 235 | 236 | /* 237 | 'path': A NULL-terminated path to a file containing kernel source. 238 | 239 | This method is equivalent to calling 240 | fLinkState *link = fraktal_link_create(); 241 | fraktal_link_add_file(link, path); 242 | fKernel *result = fraktal_link_kernel(link); 243 | */ 244 | FRAKTALAPI fKernel *fraktal_load_kernel(const char *path); 245 | 246 | /* 247 | Calling this function modifies the GPU state of the current context 248 | as required by fraktal_run_kernel and fraktal_param* functions. The 249 | state should be restored by calling this function with NULL. 250 | 251 | A kernel can be run multiple times while in use. Switching kernels 252 | does not require the state to be restored, for example: 253 | fraktal_use_kernel(a); 254 | fraktal_run_kernel(a); 255 | fraktal_use_kernel(b); 256 | fraktal_run_kernel(b); 257 | fraktal_use_kernel(NULL); 258 | runs two kernels 'a' and 'b' and properly restores the GPU state. 259 | */ 260 | FRAKTALAPI void fraktal_use_kernel(fKernel *f); 261 | 262 | /* 263 | Launches a number of concurrent GPU threads each running the current 264 | kernel (set by fraktal_use_kernel) and adds the results to 'out'. 265 | 266 | The number of threads is determined from the dimensions of 'out': 267 | * A 1D array of width w launches a sequence of threads with indices 268 | [0, 1, ..., w-1]. 269 | 270 | * A 2D array of dimensions (w,h) launches a 2D grid of threads with 271 | indices [0, w-1] x [0, h-1]. 272 | 273 | Results are **added** to the values in 'out'. The array may be 274 | cleared to zero using fraktal_zero_array(out). 275 | */ 276 | FRAKTALAPI void fraktal_run_kernel(fArray *out); 277 | 278 | //----------------------------------------------------------------------------- 279 | // §4 Parameters 280 | //----------------------------------------------------------------------------- 281 | 282 | /* 283 | The value -1 is returned if 'name' refers to a non-existent 284 | or unused parameter. 285 | */ 286 | FRAKTALAPI int fraktal_get_param_offset(fKernel *f, const char *name); 287 | 288 | FRAKTALAPI void fraktal_param_1f(int offset, float x); 289 | FRAKTALAPI void fraktal_param_2f(int offset, float x, float y); 290 | FRAKTALAPI void fraktal_param_3f(int offset, float x, float y, float z); 291 | FRAKTALAPI void fraktal_param_4f(int offset, float x, float y, float z, float w); 292 | FRAKTALAPI void fraktal_param_1i(int offset, int x); 293 | FRAKTALAPI void fraktal_param_2i(int offset, int x, int y); 294 | FRAKTALAPI void fraktal_param_3i(int offset, int x, int y, int z); 295 | FRAKTALAPI void fraktal_param_4i(int offset, int x, int y, int z, int w); 296 | FRAKTALAPI void fraktal_param_array(int offset, fArray *a); 297 | 298 | /* 299 | Matrices are assumed to be laid out in column major order, where the 300 | element at (row, column) is m[row + 4*column]. The transpose method 301 | accepts matrices in row major order, where element (row, column) is 302 | m[column + 4*row]. 303 | 304 | For example, a static array (e.g. float m[16] = { 0, 1, ..., 15 }) 305 | has the corresponding matrix interpretation: 306 | 307 | Column major Row major 308 | 0 4 8 12 0 1 2 3 309 | 1 5 9 13 4 5 6 7 310 | 2 6 10 14 8 9 10 11 311 | 3 7 11 15 12 13 14 15 312 | */ 313 | FRAKTALAPI void fraktal_param_matrix4f(int offset, float m[4*4]); 314 | FRAKTALAPI void fraktal_param_transpose_matrix4f(int offset, float m[4*4]); 315 | 316 | //----------------------------------------------------------------------------- 317 | // §5 Context management 318 | //----------------------------------------------------------------------------- 319 | 320 | /* 321 | fraktal needs a GPU context to be bound to the calling thread in 322 | order to use GPU resources. You must create this context using 323 | fraktal_create_context. 324 | 325 | Caveat: If other libraries are accessing the GPU on the same thread, 326 | you may wish to share their context so that GPU resources are visible 327 | between them. You can achieve this by NOT calling fraktal_create_context. 328 | In this case, you are responsible for ensuring that a context is current 329 | on the thread when calling fraktal functions. 330 | 331 | If for some reason you do not wish to share their context, you can 332 | call fraktal_create_context and use fraktal_push/pop_current_context 333 | to manage which library has access to the GPU (usually, only one 334 | context can be current on the same OS thread). 335 | */ 336 | 337 | FRAKTALAPI bool fraktal_create_context(); 338 | FRAKTALAPI void fraktal_destroy_context(); 339 | 340 | /* 341 | Saves the current GPU context on the calling thread and makes the 342 | fraktal GPU context current. Use this if another library accesses 343 | the GPU on the same thread. 344 | */ 345 | FRAKTALAPI void fraktal_push_current_context(); 346 | 347 | /* 348 | Pops the fraktal context from the calling thread and restores the 349 | previously current context. Use this if another library accesses 350 | the GPU on the same thread (restore their context). 351 | */ 352 | FRAKTALAPI void fraktal_pop_current_context(); 353 | 354 | #ifdef __cplusplus 355 | } 356 | #endif 357 | -------------------------------------------------------------------------------- /src/fraktal_array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "reuse/log.h" 3 | 4 | struct fArray 5 | { 6 | GLuint fbo; 7 | GLuint color0; 8 | int width; 9 | int height; 10 | int depth; 11 | int channels; 12 | fEnum format; 13 | fEnum access; 14 | }; 15 | 16 | static bool fraktal_format_to_gl_format(int channels, 17 | fEnum format, 18 | GLenum *internal_format, 19 | GLenum *data_format, 20 | GLenum *data_type) 21 | { 22 | if (format == FRAKTAL_FLOAT) 23 | { 24 | *data_type = GL_FLOAT; 25 | if (channels == 1) { *internal_format = GL_R32F; *data_format = GL_RED; return true; } 26 | else if (channels == 2) { *internal_format = GL_RG32F; *data_format = GL_RG; return true; } 27 | else if (channels == 4) { *internal_format = GL_RGBA32F; *data_format = GL_RGBA; return true; } 28 | } 29 | else if (format == FRAKTAL_UINT8) 30 | { 31 | *data_type = GL_UNSIGNED_BYTE; 32 | if (channels == 1) { *internal_format = GL_R8; *data_format = GL_RED; return true; } 33 | else if (channels == 2) { *internal_format = GL_RG8; *data_format = GL_RG; return true; } 34 | else if (channels == 4) { *internal_format = GL_RGBA8; *data_format = GL_RGBA; return true; } 35 | } 36 | return false; 37 | } 38 | 39 | fArray *fraktal_create_array( 40 | const void *data, 41 | int channels, 42 | int width, 43 | int height, 44 | int depth, 45 | fEnum format, 46 | fEnum access) 47 | { 48 | fraktal_ensure_context(); 49 | fraktal_check_gl_error(); 50 | fraktal_assert(channels > 0 && channels <= 4); 51 | fraktal_assert(width > 0 && height > 0 && depth > 0); 52 | fraktal_assert(access == FRAKTAL_READ_ONLY || access == FRAKTAL_READ_WRITE); 53 | fraktal_assert(channels == 1 || channels == 2 || channels == 4); 54 | 55 | GLenum internal_format,data_format,data_type; 56 | fraktal_assert(fraktal_format_to_gl_format(channels, format, &internal_format, &data_format, &data_type) && "Invalid array format"); 57 | 58 | GLenum target; 59 | if (width > 1 && height > 1 && depth > 1) 60 | { 61 | fraktal_assert(access == FRAKTAL_READ_ONLY && "3D arrays must be read-only."); 62 | target = GL_TEXTURE_3D; 63 | } 64 | else if (width > 1 && height > 1) 65 | { 66 | target = GL_TEXTURE_2D; 67 | } 68 | else 69 | { 70 | target = GL_TEXTURE_1D; 71 | } 72 | 73 | GLuint color0 = 0; 74 | { 75 | glGenTextures(1, &color0); 76 | glBindTexture(target, color0); 77 | if (target == GL_TEXTURE_1D) 78 | { 79 | glTexImage1D(target, 0, internal_format, width, 0, data_format, data_type, data); 80 | glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 81 | } 82 | else if (target == GL_TEXTURE_2D) 83 | { 84 | glTexImage2D(target, 0, internal_format, width, height, 0, data_format, data_type, data); 85 | glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 86 | glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 87 | } 88 | else if (target == GL_TEXTURE_3D) 89 | { 90 | glTexImage3D(target, 0, internal_format, width, height, depth, 0, data_format, data_type, data); 91 | glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 92 | glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 93 | glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); 94 | } 95 | glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 96 | glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 97 | glBindTexture(target, 0); 98 | if (glGetError() != GL_NO_ERROR) 99 | { 100 | glDeleteTextures(1, &color0); 101 | log_err("Failed to create OpenGL texture object.\n"); 102 | return NULL; 103 | } 104 | } 105 | 106 | GLuint fbo = 0; 107 | if (access == FRAKTAL_READ_WRITE) 108 | { 109 | glGenFramebuffers(1, &fbo); 110 | glBindFramebuffer(GL_FRAMEBUFFER, fbo); 111 | fraktal_assert(target == GL_TEXTURE_1D || target == GL_TEXTURE_2D); 112 | if (target == GL_TEXTURE_1D) 113 | glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, color0, 0); 114 | else if (target == GL_TEXTURE_2D) 115 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, color0, 0); 116 | glBindFramebuffer(GL_FRAMEBUFFER, 0); 117 | if (glGetError() != GL_NO_ERROR) 118 | { 119 | glDeleteFramebuffers(1, &fbo); 120 | glDeleteTextures(1, &color0); 121 | log_err("Failed to create framebuffer object.\n"); 122 | return NULL; 123 | } 124 | } 125 | 126 | fArray *a = (fArray*)calloc(1, sizeof(fArray)); 127 | a->color0 = color0; 128 | a->fbo = fbo; 129 | a->channels = channels; 130 | a->width = width; 131 | a->height = height; 132 | a->depth = depth; 133 | a->format = format; 134 | a->access = access; 135 | fraktal_check_gl_error(); 136 | return a; 137 | } 138 | 139 | void fraktal_destroy_array(fArray *a) 140 | { 141 | if (a) 142 | { 143 | fraktal_ensure_context(); 144 | fraktal_check_gl_error(); 145 | glDeleteTextures(1, &a->color0); 146 | glDeleteFramebuffers(1, &a->fbo); 147 | free(a); 148 | fraktal_check_gl_error(); 149 | } 150 | } 151 | 152 | void fraktal_zero_array(fArray *a) 153 | { 154 | fraktal_assert(a); 155 | fraktal_assert(a->access == FRAKTAL_READ_WRITE); 156 | fraktal_assert(a->fbo); 157 | fraktal_assert(a->color0); 158 | fraktal_ensure_context(); 159 | fraktal_check_gl_error(); 160 | GLint last_framebuffer; glGetIntegerv(GL_FRAMEBUFFER_BINDING, &last_framebuffer); 161 | glBindFramebuffer(GL_FRAMEBUFFER, a->fbo); 162 | glClearColor(0,0,0,0); 163 | glClear(GL_COLOR_BUFFER_BIT); 164 | glBindFramebuffer(GL_FRAMEBUFFER, last_framebuffer); 165 | fraktal_check_gl_error(); 166 | } 167 | 168 | void fraktal_to_cpu(void *cpu_memory, fArray *a) 169 | { 170 | fraktal_assert(cpu_memory); 171 | fraktal_assert(a); 172 | fraktal_assert(a->color0); 173 | fraktal_ensure_context(); 174 | fraktal_check_gl_error(); 175 | GLenum target = a->height == 1 ? GL_TEXTURE_1D : GL_TEXTURE_2D; 176 | GLenum internal_format,data_format,data_type; 177 | fraktal_assert(fraktal_format_to_gl_format(a->channels, a->format, &internal_format, &data_format, &data_type)); 178 | glPixelStorei(GL_PACK_ALIGNMENT, 1); 179 | glBindTexture(target, a->color0); 180 | glGetTexImage(target, 0, data_format, data_type, cpu_memory); 181 | glBindTexture(target, 0); 182 | fraktal_check_gl_error(); 183 | } 184 | 185 | void fraktal_array_size(fArray *a, int *width, int *height, int *depth) 186 | { 187 | if (a) 188 | { 189 | if (width) *width = a->width; 190 | if (height) *height = a->height; 191 | if (depth) *depth = a->depth; 192 | } 193 | } 194 | 195 | int fraktal_array_channels(fArray *a) 196 | { 197 | if (a) return a->channels; 198 | return 0; 199 | } 200 | 201 | fEnum fraktal_array_format(fArray *a) 202 | { 203 | if (a) return a->format; 204 | return -1; 205 | } 206 | 207 | bool fraktal_is_valid_array(fArray *a) 208 | { 209 | return a && 210 | a->width > 0 && 211 | a->height > 0 && 212 | a->depth > 0 && 213 | (a->channels == 1 || a->channels == 2 || a->channels == 4) && 214 | (a->access == FRAKTAL_READ_ONLY || (a->access == FRAKTAL_READ_WRITE && a->fbo)) && 215 | (a->format == FRAKTAL_FLOAT || a->format == FRAKTAL_UINT8); 216 | } 217 | 218 | unsigned int fraktal_get_gl_handle(fArray *a) 219 | { 220 | return a->color0; 221 | } 222 | -------------------------------------------------------------------------------- /src/fraktal_context.h: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | #pragma once 5 | #include "reuse/log.h" 6 | #include "reuse/glfw/include/GLFW/glfw3.h" 7 | 8 | // Required to link with vc2010 GLFW 9 | #if defined(_MSC_VER) && (_MSC_VER >= 1900) 10 | #pragma comment(lib, "legacy_stdio_definitions") 11 | #endif 12 | 13 | static void fraktal_glfw_error_callback(int error, const char* description) 14 | { 15 | fprintf(stderr, "Fraktal GLFW error %d: %s\n", error, description); 16 | } 17 | 18 | static GLFWwindow *fraktal_context = NULL; 19 | static bool fraktal_gl_symbols_loaded = false; 20 | static const char *fraktal_glsl_version = "#version 150"; 21 | 22 | bool fraktal_create_context() 23 | { 24 | fraktal_assert(!fraktal_context && "A context already exists."); 25 | glfwSetErrorCallback(fraktal_glfw_error_callback); 26 | if (!glfwInit()) 27 | return false; 28 | 29 | #if __APPLE__ 30 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 31 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); 32 | glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only 33 | glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true); // Required on Mac 34 | #else 35 | glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 36 | glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); 37 | #endif 38 | glfwWindowHint(GLFW_VISIBLE, false); 39 | 40 | fraktal_context = glfwCreateWindow(32, 32, "fraktal", NULL, NULL); 41 | if (fraktal_context == NULL) 42 | { 43 | fprintf(stderr, "Error creating context: failed to create GLFW window.\n"); 44 | return false; 45 | } 46 | return true; 47 | } 48 | 49 | void fraktal_destroy_context() 50 | { 51 | if (fraktal_context) 52 | glfwDestroyWindow(fraktal_context); 53 | fraktal_context = NULL; 54 | } 55 | 56 | void fraktal_push_current_context() 57 | { 58 | if (fraktal_context) 59 | glfwMakeContextCurrent(fraktal_context); 60 | } 61 | 62 | void fraktal_pop_current_context() 63 | { 64 | if (fraktal_context) 65 | glfwMakeContextCurrent(NULL); 66 | } 67 | 68 | static void fraktal_ensure_context() 69 | { 70 | if (fraktal_context) 71 | glfwMakeContextCurrent(fraktal_context); 72 | // else: we expect the caller to have made a context current 73 | // on the thread 74 | 75 | if (!fraktal_gl_symbols_loaded) 76 | { 77 | fraktal_gl_symbols_loaded = true; 78 | if (gl3wInit() != 0) 79 | fraktal_assert(false && "Failed to load OpenGL symbols."); 80 | } 81 | 82 | // verify that we have OpenGL symbols loaded by testing one 83 | // of the function pointers 84 | fraktal_assert(glCreateShader != NULL && "Failed to load OpenGL symbols."); 85 | } 86 | -------------------------------------------------------------------------------- /src/fraktal_kernel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "reuse/log.h" 5 | 6 | struct fKernel 7 | { 8 | GLuint program; 9 | int loc_iPosition; 10 | fParams params; 11 | }; 12 | 13 | static fKernel *fraktal_current_kernel = NULL; 14 | 15 | int fraktal_get_param_offset(fKernel *f, const char *name) 16 | { 17 | fraktal_assert(name); 18 | fraktal_assert(f); 19 | fraktal_assert(f->program); 20 | fraktal_ensure_context(); 21 | for (int i = 0; i < f->params.count; i++) 22 | if (strcmp(f->params.name[i], name) == 0) 23 | return f->params.offset[i]; 24 | return -1; 25 | } 26 | 27 | void fraktal_use_kernel(fKernel *f) 28 | { 29 | fraktal_ensure_context(); 30 | fraktal_check_gl_error(); 31 | static GLint last_program; 32 | static GLint last_array_buffer; 33 | static GLint last_vertex_array; 34 | static GLint last_viewport[4]; 35 | static GLint last_scissor_box[4]; 36 | static GLint last_framebuffer; 37 | static GLenum last_blend_src_rgb; 38 | static GLenum last_blend_dst_rgb; 39 | static GLenum last_blend_src_alpha; 40 | static GLenum last_blend_dst_alpha; 41 | static GLenum last_blend_equation_rgb; 42 | static GLenum last_blend_equation_alpha; 43 | static GLboolean last_depth_writemask; 44 | static GLenum last_enable_blend; 45 | static GLenum last_enable_cull_face; 46 | static GLenum last_enable_depth_test; 47 | static GLenum last_enable_scissor_test; 48 | static GLenum last_enable_color_logic_op; 49 | static GLuint vao = 0; 50 | 51 | static GLuint quad = 0; 52 | if (!quad) 53 | { 54 | static const float data[] = { -1,-1, +1,-1, +1,+1, +1,+1, -1,+1, -1,-1 }; 55 | glGenBuffers(1, &quad); 56 | glBindBuffer(GL_ARRAY_BUFFER, quad); 57 | glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); 58 | glBindBuffer(GL_ARRAY_BUFFER, 0); 59 | } 60 | fraktal_assert(quad && "Failed to create vertex buffer"); 61 | 62 | if (f) 63 | { 64 | fraktal_assert(glIsProgram(f->program) && "f must be a valid kernel object"); 65 | } 66 | 67 | if (fraktal_current_kernel) 68 | { 69 | if (f) 70 | { 71 | fraktal_current_kernel = f; 72 | glUseProgram(f->program); 73 | if (!f->loc_iPosition) 74 | f->loc_iPosition = glGetAttribLocation(f->program, "iPosition"); 75 | fraktal_assert(f->loc_iPosition >= 0); 76 | glEnableVertexAttribArray(f->loc_iPosition); 77 | glVertexAttribPointer(f->loc_iPosition, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, 0); 78 | } 79 | else 80 | { 81 | glDisableVertexAttribArray(fraktal_current_kernel->loc_iPosition); 82 | glDeleteVertexArrays(1, &vao); 83 | fraktal_current_kernel = NULL; 84 | 85 | // Restore GL state 86 | glUseProgram(last_program); 87 | glBindVertexArray(last_vertex_array); 88 | glBindBuffer(GL_ARRAY_BUFFER, last_array_buffer); 89 | glBlendEquationSeparate(last_blend_equation_rgb, last_blend_equation_alpha); 90 | glBlendFuncSeparate(last_blend_src_rgb, last_blend_dst_rgb, last_blend_src_alpha, last_blend_dst_alpha); 91 | glBindFramebuffer(GL_FRAMEBUFFER, last_framebuffer); 92 | if (last_enable_blend) glEnable(GL_BLEND); else glDisable(GL_BLEND); 93 | if (last_enable_cull_face) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); 94 | if (last_enable_depth_test) glEnable(GL_DEPTH_TEST); else glDisable(GL_DEPTH_TEST); 95 | if (last_enable_scissor_test) glEnable(GL_SCISSOR_TEST); else glDisable(GL_SCISSOR_TEST); 96 | if (last_enable_color_logic_op) glEnable(GL_COLOR_LOGIC_OP); else glDisable(GL_COLOR_LOGIC_OP); 97 | glViewport(last_viewport[0], last_viewport[1], (GLsizei)last_viewport[2], (GLsizei)last_viewport[3]); 98 | glScissor(last_scissor_box[0], last_scissor_box[1], (GLsizei)last_scissor_box[2], (GLsizei)last_scissor_box[3]); 99 | glActiveTexture(GL_TEXTURE0); 100 | } 101 | } 102 | else 103 | { 104 | if (f) 105 | { 106 | // Back-up GL state 107 | glGetIntegerv(GL_CURRENT_PROGRAM, &last_program); 108 | glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &last_array_buffer); 109 | glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vertex_array); 110 | glGetIntegerv(GL_VIEWPORT, last_viewport); 111 | glGetIntegerv(GL_SCISSOR_BOX, last_scissor_box); 112 | glGetIntegerv(GL_FRAMEBUFFER_BINDING, &last_framebuffer); 113 | glGetIntegerv(GL_BLEND_SRC_RGB, (GLint*)&last_blend_src_rgb); 114 | glGetIntegerv(GL_BLEND_DST_RGB, (GLint*)&last_blend_dst_rgb); 115 | glGetIntegerv(GL_BLEND_SRC_ALPHA, (GLint*)&last_blend_src_alpha); 116 | glGetIntegerv(GL_BLEND_DST_ALPHA, (GLint*)&last_blend_dst_alpha); 117 | glGetIntegerv(GL_BLEND_EQUATION_RGB, (GLint*)&last_blend_equation_rgb); 118 | glGetIntegerv(GL_BLEND_EQUATION_ALPHA, (GLint*)&last_blend_equation_alpha); 119 | glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean*)&last_depth_writemask); 120 | last_enable_blend = glIsEnabled(GL_BLEND); 121 | last_enable_cull_face = glIsEnabled(GL_CULL_FACE); 122 | last_enable_depth_test = glIsEnabled(GL_DEPTH_TEST); 123 | last_enable_scissor_test = glIsEnabled(GL_SCISSOR_TEST); 124 | last_enable_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); 125 | 126 | fraktal_current_kernel = f; 127 | glDisable(GL_CULL_FACE); 128 | glDisable(GL_DEPTH_TEST); 129 | glDisable(GL_SCISSOR_TEST); 130 | glDisable(GL_COLOR_LOGIC_OP); 131 | glEnable(GL_BLEND); 132 | glBlendFunc(GL_ONE, GL_ONE); 133 | glBlendEquation(GL_FUNC_ADD); 134 | glGenVertexArrays(1, &vao); 135 | glBindVertexArray(vao); 136 | glBindBuffer(GL_ARRAY_BUFFER, quad); 137 | 138 | glUseProgram(f->program); 139 | if (!f->loc_iPosition) 140 | f->loc_iPosition = glGetAttribLocation(f->program, "iPosition"); 141 | fraktal_assert(f->loc_iPosition >= 0); 142 | glEnableVertexAttribArray(f->loc_iPosition); 143 | glVertexAttribPointer(f->loc_iPosition, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, 0); 144 | } 145 | else 146 | { 147 | // do nothing 148 | } 149 | } 150 | fraktal_check_gl_error(); 151 | } 152 | 153 | void fraktal_param_1f(int offset, float x) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniform1f(offset, x); } 154 | void fraktal_param_2f(int offset, float x, float y) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniform2f(offset, x, y); } 155 | void fraktal_param_3f(int offset, float x, float y, float z) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniform3f(offset, x, y, z); } 156 | void fraktal_param_4f(int offset, float x, float y, float z, float w) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniform4f(offset, x, y, z, w); } 157 | void fraktal_param_1i(int offset, int x) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniform1i(offset, x); } 158 | void fraktal_param_2i(int offset, int x, int y) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniform2i(offset, x, y); } 159 | void fraktal_param_3i(int offset, int x, int y, int z) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniform3i(offset, x, y, z); } 160 | void fraktal_param_4i(int offset, int x, int y, int z, int w) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniform4i(offset, x, y, z, w); } 161 | void fraktal_param_matrix4f(int offset, float m[4*4]) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniformMatrix4fv(offset, 1, false, m); } 162 | void fraktal_param_transpose_matrix4f(int offset, float m[4*4]) { fraktal_assert(fraktal_current_kernel); if (offset < 0) return; glUniformMatrix4fv(offset, 1, true, m); } 163 | 164 | void fraktal_param_array(int offset, fArray *a) 165 | { 166 | fraktal_assert(a); 167 | fraktal_assert(a->color0); 168 | fraktal_assert(a->width > 0 && a->height > 0 && a->depth > 0 && "Array has invalid dimensions."); 169 | fraktal_assert(fraktal_current_kernel); 170 | if (offset < 0) 171 | return; 172 | int tex_unit = -1; 173 | { 174 | fParams *p = &fraktal_current_kernel->params; 175 | for (int i = 0; i < p->count; i++) 176 | if (p->offset[i] == offset) 177 | tex_unit = p->assigned_tex_unit[i]; 178 | fraktal_assert(tex_unit >= 0 && "Array parameter with unassigned texture unit."); 179 | } 180 | glUniform1i(offset, tex_unit); 181 | glActiveTexture(GL_TEXTURE0 + tex_unit); 182 | if (a->width > 1 && a->height > 1 && a->depth > 1) 183 | glBindTexture(GL_TEXTURE_3D, a->color0); 184 | else if (a->width > 1 && a->height > 1) 185 | glBindTexture(GL_TEXTURE_2D, a->color0); 186 | else if (a->width > 1) 187 | glBindTexture(GL_TEXTURE_1D, a->color0); 188 | else 189 | fraktal_assert(false && "Invalid array dimensions"); 190 | } 191 | 192 | void fraktal_run_kernel(fArray *out) 193 | { 194 | fraktal_assert(fraktal_current_kernel && "Call fraktal_use_kernel first."); 195 | fraktal_assert(out); 196 | fraktal_assert(out->width > 0); 197 | fraktal_assert(out->height > 0); 198 | fraktal_assert(out->depth == 1 && "Output array must be 1D or 2D."); 199 | fraktal_assert(out->fbo && "The output array's access mode cannot be read-only."); 200 | fraktal_assert(out->color0); 201 | fraktal_ensure_context(); 202 | fraktal_check_gl_error(); 203 | 204 | glBindFramebuffer(GL_FRAMEBUFFER, out->fbo); 205 | if (out->height == 0) 206 | glViewport(0, 0, out->width, 1); 207 | else 208 | glViewport(0, 0, out->width, out->height); 209 | glDrawArrays(GL_TRIANGLES, 0, 6); 210 | fraktal_check_gl_error(); 211 | } 212 | -------------------------------------------------------------------------------- /src/fraktal_link.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "reuse/file.h" 4 | #include "reuse/log.h" 5 | 6 | enum { MAX_LINK_STATE_ITEMS = 1024 }; 7 | struct fLinkState 8 | { 9 | const char *glsl_version; 10 | GLuint shaders[MAX_LINK_STATE_ITEMS]; 11 | int num_shaders; 12 | fParams params; 13 | }; 14 | 15 | static GLuint compile_shader(const char *name, const char **sources, int num_sources, GLenum type) 16 | { 17 | fraktal_ensure_context(); 18 | fraktal_check_gl_error(); 19 | fraktal_assert(sources && "Missing shader source list"); 20 | fraktal_assert(num_sources > 0 && "Must have atleast one shader"); 21 | fraktal_assert((type == GL_VERTEX_SHADER || type == GL_FRAGMENT_SHADER)); 22 | if (!name) 23 | name = "unnamed"; 24 | 25 | GLuint shader = glCreateShader(type); 26 | if (!shader) 27 | { 28 | log_err("Failed to compile shader (%s): glCreateShader returned 0.\n", name); 29 | return 0; 30 | } 31 | 32 | glShaderSource(shader, num_sources, (const GLchar **)sources, 0); 33 | glCompileShader(shader); 34 | 35 | GLint status = 0; 36 | glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 37 | if (!status) 38 | { 39 | GLint length; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); 40 | char *info = (char*)malloc(length); 41 | glGetShaderInfoLog(shader, length, NULL, info); 42 | log_err("Failed to compile shader (%s):\n%s", name, info); 43 | free(info); 44 | glDeleteShader(shader); 45 | return 0; 46 | } 47 | fraktal_check_gl_error(); 48 | return shader; 49 | } 50 | 51 | static bool program_link_status(GLuint program) 52 | { 53 | fraktal_ensure_context(); 54 | fraktal_check_gl_error(); 55 | GLint status; glGetProgramiv(program, GL_LINK_STATUS, &status); 56 | if (!status) 57 | { 58 | GLint length; 59 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length); 60 | char *info = (char*)malloc(length); 61 | glGetProgramInfoLog(program, length, NULL, info); 62 | log_err("Failed to link program:\n%s", info); 63 | free(info); 64 | return false; 65 | } 66 | fraktal_check_gl_error(); 67 | return true; 68 | } 69 | 70 | static bool add_link_data(fLinkState *link, char *data, const char *name) 71 | { 72 | fraktal_assert(link); 73 | fraktal_assert(link->num_shaders < MAX_LINK_STATE_ITEMS); 74 | fraktal_assert(link->glsl_version); 75 | fraktal_assert(data && "'data' must be a non-NULL pointer to a buffer containing kernel source text."); 76 | fraktal_ensure_context(); 77 | fraktal_check_gl_error(); 78 | if (!parse_fraktal_source(data, &link->params, name)) 79 | { 80 | log_err("Error parsing kernel source\n"); 81 | return false; 82 | } 83 | const char *sources[] = { 84 | link->glsl_version, 85 | "\nuniform int Dummy;\n" 86 | "#define ZERO (min(0, Dummy))\n" 87 | #ifdef FRAKTAL_GUI 88 | "#define FRAKTAL_GUI\n" 89 | #endif 90 | "\n#line 0\n", 91 | (const char*)data, 92 | }; 93 | int num_sources = sizeof(sources)/sizeof(sources[0]); 94 | GLuint shader = compile_shader(name, sources, num_sources, GL_FRAGMENT_SHADER); 95 | if (!shader) 96 | return false; 97 | link->shaders[link->num_shaders++] = shader; 98 | fraktal_check_gl_error(); 99 | return true; 100 | } 101 | 102 | fLinkState *fraktal_create_link() 103 | { 104 | fraktal_ensure_context(); 105 | fLinkState *link = (fLinkState*)malloc(sizeof(fLinkState)); 106 | link->num_shaders = 0; 107 | link->glsl_version = "#version 150"; 108 | link->params.count = 0; 109 | link->params.sampler_count = 0; 110 | return link; 111 | } 112 | 113 | void fraktal_destroy_link(fLinkState *link) 114 | { 115 | if (link) 116 | { 117 | fraktal_ensure_context(); 118 | fraktal_check_gl_error(); 119 | for (int i = 0; i < link->num_shaders; i++) 120 | if (link->shaders[i]) 121 | glDeleteShader(link->shaders[i]); 122 | free(link); 123 | fraktal_check_gl_error(); 124 | } 125 | } 126 | 127 | bool fraktal_add_link_data(fLinkState *link, const char *data, unsigned int size, const char *name) 128 | { 129 | // cannot assume that we are allowed to modify user data, so we make a copy. 130 | if (size == 0) size = (unsigned int)strlen(data); 131 | char *copy = (char*)malloc(size + 1); 132 | strcpy(copy, data); 133 | fraktal_assert(copy && "Ran out of memory"); 134 | bool result = add_link_data(link, copy, name); 135 | free(copy); 136 | return result; 137 | } 138 | 139 | bool fraktal_add_link_file(fLinkState *link, const char *path) 140 | { 141 | char *data = read_file(path); 142 | if (!data) 143 | { 144 | log_err("Failed to open file '%s'\n", path); 145 | return false; 146 | } 147 | bool result = add_link_data(link, data, path); 148 | free(data); 149 | return result; 150 | } 151 | 152 | fKernel *fraktal_link_kernel(fLinkState *link) 153 | { 154 | fraktal_assert(link); 155 | fraktal_ensure_context(); 156 | fraktal_check_gl_error(); 157 | if (link->num_shaders <= 0) 158 | return NULL; 159 | 160 | static GLuint vs = 0; 161 | if (!vs) 162 | { 163 | static const char *source = 164 | "in vec2 iPosition;\n" 165 | "void main()\n" 166 | "{\n" 167 | " gl_Position = vec4(iPosition, 0.0, 1.0);\n" 168 | "}\n" 169 | ; 170 | const char *sources[] = { link->glsl_version, "\n#line 0\n", source }; 171 | vs = compile_shader("built-in vertex shader", sources, sizeof(sources)/sizeof(char*), GL_VERTEX_SHADER); 172 | } 173 | if (!vs) 174 | { 175 | log_err("Failed to link kernel\n"); 176 | return NULL; 177 | } 178 | 179 | GLuint program = glCreateProgram(); 180 | glAttachShader(program, vs); 181 | for (int i = 0; i < link->num_shaders; i++) 182 | glAttachShader(program, link->shaders[i]); 183 | glLinkProgram(program); 184 | glDetachShader(program, vs); 185 | for (int i = 0; i < link->num_shaders; i++) 186 | glDetachShader(program, link->shaders[i]); 187 | 188 | if (!program_link_status(program)) 189 | { 190 | glDeleteProgram(program); 191 | log_err("Failed to link kernel\n"); 192 | return NULL; 193 | } 194 | 195 | fKernel *kernel = (fKernel*)malloc(sizeof(fKernel)); 196 | kernel->program = program; 197 | kernel->params.count = link->params.count; 198 | kernel->params.sampler_count = link->params.sampler_count; 199 | kernel->loc_iPosition = 0; 200 | for (int i = 0; i < link->params.count; i++) 201 | { 202 | strcpy(kernel->params.name[i], link->params.name[i]); 203 | kernel->params.type[i] = link->params.type[i]; 204 | kernel->params.mean[i] = link->params.mean[i]; 205 | kernel->params.scale[i] = link->params.scale[i]; 206 | kernel->params.offset[i] = glGetUniformLocation(program, link->params.name[i]); 207 | kernel->params.assigned_tex_unit[i] = link->params.assigned_tex_unit[i]; 208 | kernel->params.std140_offset[i] = link->params.std140_offset[i]; 209 | kernel->params.std140_size[i] = link->params.std140_size[i]; 210 | } 211 | // print kernel information 212 | #if 0 213 | { 214 | for (int i = 0; i < kernel->params.count; i++) 215 | { 216 | printf("%s: ", kernel->params.name[i]); 217 | printf("%d: ", kernel->params.offset[i]); 218 | printf("%d: ", kernel->params.type[i]); 219 | printf("%f: ", kernel->params.mean[i].x); 220 | printf("%f: ", kernel->params.scale[i].x); 221 | printf("%d: ", kernel->params.assigned_tex_unit[i]); 222 | printf("%d: ", kernel->params.std140_offset[i]); 223 | printf("%d: ", kernel->params.std140_size[i]); 224 | printf("\n"); 225 | } 226 | printf("num_params: %d\n", kernel->params.count); 227 | printf("num_samplers: %d\n", kernel->params.sampler_count); 228 | } 229 | #endif 230 | fraktal_check_gl_error(); 231 | return kernel; 232 | } 233 | 234 | void fraktal_destroy_kernel(fKernel *f) 235 | { 236 | if (f) 237 | { 238 | fraktal_ensure_context(); 239 | fraktal_check_gl_error(); 240 | if (f->program) 241 | glDeleteProgram(f->program); 242 | free(f); 243 | fraktal_check_gl_error(); 244 | } 245 | } 246 | 247 | fKernel *fraktal_load_kernel(const char *path) 248 | { 249 | fraktal_assert(path); 250 | fLinkState *link = fraktal_create_link(); 251 | fraktal_add_link_file(link, path); 252 | return fraktal_link_kernel(link); 253 | } 254 | -------------------------------------------------------------------------------- /src/fraktal_types.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | typedef float angle; 5 | struct int2 { int x,y; }; 6 | struct int3 { int x,y,z; }; 7 | struct int4 { int x,y,z,w; }; 8 | struct angle2 { angle theta,phi; }; 9 | struct float2 { float x,y; }; 10 | struct float3 { float x,y,z; }; 11 | struct float4 { float x,y,z,w; }; 12 | 13 | static float deg2rad(float deg) { return (3.14159265358979f/180.0f)*deg; } 14 | static float yfov2pinhole_f(float yfov, float resolution_y) 15 | { 16 | return (resolution_y/2.0f) / tanf(deg2rad(yfov)/2.0f); 17 | } 18 | 19 | static float3 angle2float3(angle2 dir) 20 | { 21 | float3 w = 22 | { 23 | sinf(deg2rad(dir.theta))*cosf(deg2rad(dir.phi)), 24 | cosf(deg2rad(dir.theta)), 25 | sinf(deg2rad(dir.theta))*sinf(deg2rad(dir.phi)), 26 | }; 27 | return w; 28 | } 29 | 30 | enum { FRAKTAL_MAX_PARAMS = 1024 }; 31 | enum { FRAKTAL_MAX_PARAM_NAME_LEN = 64 }; 32 | typedef int fParamType; 33 | enum fParamType_ 34 | { 35 | FRAKTAL_PARAM_FLOAT, 36 | FRAKTAL_PARAM_FLOAT_VEC2, 37 | FRAKTAL_PARAM_FLOAT_VEC3, 38 | FRAKTAL_PARAM_FLOAT_VEC4, 39 | FRAKTAL_PARAM_FLOAT_MAT2, 40 | FRAKTAL_PARAM_FLOAT_MAT3, 41 | FRAKTAL_PARAM_FLOAT_MAT4, 42 | FRAKTAL_PARAM_INT, 43 | FRAKTAL_PARAM_INT_VEC2, 44 | FRAKTAL_PARAM_INT_VEC3, 45 | FRAKTAL_PARAM_INT_VEC4, 46 | FRAKTAL_PARAM_SAMPLER1D, 47 | FRAKTAL_PARAM_SAMPLER2D, 48 | FRAKTAL_PARAM_SAMPLER3D, 49 | }; 50 | struct fParams 51 | { 52 | float4 mean[FRAKTAL_MAX_PARAMS]; 53 | float4 scale[FRAKTAL_MAX_PARAMS]; 54 | char name[FRAKTAL_MAX_PARAMS][FRAKTAL_MAX_PARAM_NAME_LEN + 1]; 55 | int offset[FRAKTAL_MAX_PARAMS]; 56 | fParamType type[FRAKTAL_MAX_PARAMS]; 57 | int assigned_tex_unit[FRAKTAL_MAX_PARAMS]; 58 | 59 | int std140_offset[FRAKTAL_MAX_PARAMS]; 60 | int std140_size[FRAKTAL_MAX_PARAMS]; 61 | 62 | int sampler_count; 63 | int count; 64 | }; 65 | -------------------------------------------------------------------------------- /src/reuse/args.h: -------------------------------------------------------------------------------- 1 | // Changelog: 2 | // 9. april 2019: No longer using strdup (availability issues across compilers). 3 | // 7. april 2019: Added arg_bool. 4 | // 7. april 2019: Added arg_get_exe_dir. Removed flags. Use arg_err in arg_help prompt. 5 | 6 | // Example usage: 7 | // int main(int argc, char **argv) 8 | // { 9 | // arg_int32(&dpi, 100, "-dpi", "DPI resolution"); 10 | // arg_string(&eqname, "eq", "-out", "Base filename of output PNGs"); 11 | // arg_int32(&ptsize, 12, "-ptsize", "Font size"); 12 | // arg_string(&input, NULL, "-i", "Input filename"); 13 | // if (!arg_parse(argc, argv)) 14 | // { 15 | // arg_help(); 16 | // return 1; 17 | // } 18 | // return 0; 19 | // } 20 | #pragma once 21 | #include 22 | void arg_int32 (int32_t *x, int32_t x0, const char *key, const char *msg); 23 | void arg_uint32 (uint32_t *x, uint32_t x0, const char *key, const char *msg); 24 | void arg_float32(float *x, float x0, const char *key, const char *msg); 25 | void arg_string (const char **x, const char *x0, const char *key, const char *msg); 26 | void arg_bool (bool *x, bool x0, const char *key, const char *msg); 27 | const char *arg_get_exe_dir(); 28 | bool arg_parse (int argc, char **argv); 29 | void arg_help (); 30 | 31 | // 32 | // implementation follows 33 | // 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #ifndef arg_err 40 | #define arg_err(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) 41 | #endif 42 | #ifndef arg_assert 43 | #include 44 | #define arg_assert assert 45 | #endif 46 | 47 | typedef int arg_type_t; 48 | enum arg_type_ 49 | { 50 | arg_type_int32 = 0, 51 | arg_type_uint32, 52 | arg_type_float32, 53 | arg_type_bool, 54 | arg_type_string 55 | }; 56 | 57 | enum { MAX_ARGS = 1024 }; 58 | 59 | struct arg_t 60 | { 61 | arg_type_t type; 62 | void *ptr; 63 | const char *msg; 64 | const char *key; // note: this should be freed, we currently don't 65 | }; 66 | 67 | struct args_t 68 | { 69 | int num_expected; 70 | const char *exe_dir; 71 | arg_t args[MAX_ARGS]; 72 | }; 73 | 74 | static args_t global_args = {0}; 75 | 76 | #define arg_routine_macro(SUFFIX, TYPENAME) \ 77 | void arg_##SUFFIX(TYPENAME *x, TYPENAME x0, const char *key, const char *msg) \ 78 | { \ 79 | *x = x0; \ 80 | arg_t arg = {0}; \ 81 | arg.type = arg_type_##SUFFIX; \ 82 | arg.ptr = x; \ 83 | arg.key = key; \ 84 | arg.msg = msg; \ 85 | assert(global_args.num_expected < MAX_ARGS); \ 86 | global_args.args[global_args.num_expected++] = arg; \ 87 | } 88 | 89 | arg_routine_macro(int32, int32_t); 90 | arg_routine_macro(uint32, uint32_t); 91 | arg_routine_macro(float32, float); 92 | arg_routine_macro(bool, bool); 93 | arg_routine_macro(string, const char*); 94 | 95 | bool arg_parse(int argc, char **argv) 96 | { 97 | if (global_args.num_expected == 0) 98 | return true; 99 | 100 | for (int i = 0; i < argc; i++) 101 | { 102 | bool match = false; 103 | size_t len_arg = strlen(argv[i]); 104 | for (int j = 0; j < global_args.num_expected; j++) 105 | { 106 | arg_t *arg = &global_args.args[j]; 107 | size_t len_key = strlen(arg->key); 108 | if (strncmp(argv[i], arg->key, len_key) == 0) 109 | { 110 | match = true; 111 | 112 | if (arg->type == arg_type_bool) 113 | { 114 | *(bool*)arg->ptr = true; 115 | break; 116 | } 117 | 118 | char *value = NULL; 119 | if (len_arg > len_key) 120 | { 121 | value = argv[i] + len_key; 122 | if (*value == '=') 123 | value++; 124 | } 125 | else if (i + 1 < argc) 126 | { 127 | value = argv[++i]; 128 | } 129 | else 130 | { 131 | arg_err("Missing value for argument '%s'.\n", argv[i]); 132 | return false; 133 | } 134 | 135 | if (arg->type == arg_type_int32) { if (1 != sscanf(value, "%d", (int32_t*)arg->ptr)) { arg_err("'%s' option expects an integer, got '%s'.\n", arg->key, value); return false; } } 136 | else if (arg->type == arg_type_uint32) { if (1 != sscanf(value, "%u", (uint32_t*)arg->ptr)) { arg_err("'%s' option expects an integer, got '%s'.\n", arg->key, value); return false; } } 137 | else if (arg->type == arg_type_float32) { if (1 != sscanf(value, "%f", (float*)arg->ptr)) { arg_err("'%s' option expects a float, got '%s'.\n", arg->key, value); return false; } } 138 | else if (arg->type == arg_type_string) *(const char**)arg->ptr = value; 139 | else arg_assert(false && "Undefined argument type"); 140 | 141 | break; 142 | } 143 | } 144 | if (!match) 145 | { 146 | if (i == 0) 147 | { 148 | char *exe_dir = (char*)malloc(strlen(argv[i]) + 1); 149 | arg_assert(exe_dir); 150 | strcpy(exe_dir, argv[i]); 151 | for (size_t j = 0; j < strlen(exe_dir); j++) 152 | { 153 | #ifdef _WIN32 154 | if (exe_dir[j] == '/') exe_dir[j] = '\\'; 155 | #else 156 | if (exe_dir[j] == '\\') exe_dir[j] = '/'; 157 | #endif 158 | } 159 | char *unix = strrchr(exe_dir, '/'); 160 | char *windows = strrchr(exe_dir, '\\'); 161 | char *last = unix > windows ? unix : windows; 162 | if (last) 163 | { 164 | last[1] = '\0'; 165 | global_args.exe_dir = exe_dir; 166 | } 167 | else 168 | { 169 | free(exe_dir); 170 | } 171 | } 172 | else 173 | { 174 | arg_err("Unrecognized argument '%s'.\n", argv[i]); 175 | return false; 176 | } 177 | } 178 | } 179 | 180 | if (!global_args.exe_dir) 181 | { 182 | #ifdef _WIN32 183 | global_args.exe_dir = ".\\"; 184 | #else 185 | global_args.exe_dir = "./"; 186 | #endif 187 | } 188 | 189 | return true; 190 | } 191 | 192 | const char *arg_get_exe_dir() 193 | { 194 | return global_args.exe_dir; 195 | } 196 | 197 | void arg_help() 198 | { 199 | for (int i = 0; i < global_args.num_expected; i++) 200 | { 201 | arg_t *arg = &global_args.args[i]; 202 | size_t len = strlen(arg->key); 203 | arg_err(" %s ", arg->key); 204 | for (size_t j = len; j < 8; j++) 205 | arg_err("%s", "."); 206 | arg_err("... %s ", arg->msg); 207 | if (arg->type == arg_type_int32) arg_err("[%d]\n", *(int32_t*)arg->ptr); 208 | else if (arg->type == arg_type_uint32) arg_err("[%u]\n", *(uint32_t*)arg->ptr); 209 | else if (arg->type == arg_type_float32) arg_err("[%f]\n", *(float*)arg->ptr); 210 | else if (arg->type == arg_type_string) arg_err("[%s]\n", *(const char**)arg->ptr); 211 | else if (arg->type == arg_type_bool) arg_err("[%s]\n", *(const char**)arg->ptr ? "true" : "false"); 212 | else arg_assert(false && "Undefined argument type"); 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /src/reuse/file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | char *read_file(const char *filename, int *out_size=NULL) 4 | { 5 | if (!filename) 6 | return NULL; 7 | FILE *f = fopen(filename, "rb"); 8 | if (!f) 9 | return NULL; 10 | fseek(f, 0, SEEK_END); 11 | long size = ftell(f); 12 | rewind(f); 13 | char *result = new char[size + 1]; 14 | if (!fread(result, 1, size, f)) 15 | return NULL; 16 | result[size] = '\0'; 17 | fclose(f); 18 | if (out_size) 19 | *out_size = size; 20 | return result; 21 | } 22 | 23 | /* 24 | Example usage: 25 | char *data = read_file(filename); 26 | char *line = read_line(&data); 27 | while (line) { 28 | // handle line 29 | line = read_line(&data); 30 | } 31 | */ 32 | char *read_line(char **s) 33 | { 34 | if (!*s) return NULL; // if the user calls read_line(&data) with data=NULL (no data) 35 | if (!**s) return NULL; // if the user calls read_line(&data) with data[0]=NULL (no line/eof) 36 | char *begin = *s; 37 | char *end = *s; 38 | while (*end && !(*end == '\n' || *end == '\r')) // while !newline 39 | end++; 40 | while (*end && (*end == '\n' || *end == '\r')) // while newline 41 | { 42 | *end = '\0'; 43 | end++; 44 | } 45 | *s = end; 46 | return begin; 47 | } 48 | -------------------------------------------------------------------------------- /src/reuse/glfw/COPYING.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002-2006 Marcus Geelnard 2 | Copyright (c) 2006-2010 Camilla Berglund 3 | 4 | This software is provided 'as-is', without any express or implied 5 | warranty. In no event will the authors be held liable for any damages 6 | arising from the use of this software. 7 | 8 | Permission is granted to anyone to use this software for any purpose, 9 | including commercial applications, and to alter it and redistribute it 10 | freely, subject to the following restrictions: 11 | 12 | 1. The origin of this software must not be misrepresented; you must not 13 | claim that you wrote the original software. If you use this software 14 | in a product, an acknowledgment in the product documentation would 15 | be appreciated but is not required. 16 | 17 | 2. Altered source versions must be plainly marked as such, and must not 18 | be misrepresented as being the original software. 19 | 20 | 3. This notice may not be removed or altered from any source 21 | distribution. 22 | 23 | -------------------------------------------------------------------------------- /src/reuse/glfw/include/GLFW/glfw3native.h: -------------------------------------------------------------------------------- 1 | /************************************************************************* 2 | * GLFW 3.2 - www.glfw.org 3 | * A library for OpenGL, window and input 4 | *------------------------------------------------------------------------ 5 | * Copyright (c) 2002-2006 Marcus Geelnard 6 | * Copyright (c) 2006-2010 Camilla Berglund 7 | * 8 | * This software is provided 'as-is', without any express or implied 9 | * warranty. In no event will the authors be held liable for any damages 10 | * arising from the use of this software. 11 | * 12 | * Permission is granted to anyone to use this software for any purpose, 13 | * including commercial applications, and to alter it and redistribute it 14 | * freely, subject to the following restrictions: 15 | * 16 | * 1. The origin of this software must not be misrepresented; you must not 17 | * claim that you wrote the original software. If you use this software 18 | * in a product, an acknowledgment in the product documentation would 19 | * be appreciated but is not required. 20 | * 21 | * 2. Altered source versions must be plainly marked as such, and must not 22 | * be misrepresented as being the original software. 23 | * 24 | * 3. This notice may not be removed or altered from any source 25 | * distribution. 26 | * 27 | *************************************************************************/ 28 | 29 | #ifndef _glfw3_native_h_ 30 | #define _glfw3_native_h_ 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif 35 | 36 | 37 | /************************************************************************* 38 | * Doxygen documentation 39 | *************************************************************************/ 40 | 41 | /*! @file glfw3native.h 42 | * @brief The header of the native access functions. 43 | * 44 | * This is the header file of the native access functions. See @ref native for 45 | * more information. 46 | */ 47 | /*! @defgroup native Native access 48 | * 49 | * **By using the native access functions you assert that you know what you're 50 | * doing and how to fix problems caused by using them. If you don't, you 51 | * shouldn't be using them.** 52 | * 53 | * Before the inclusion of @ref glfw3native.h, you may define exactly one 54 | * window system API macro and zero or more context creation API macros. 55 | * 56 | * The chosen backends must match those the library was compiled for. Failure 57 | * to do this will cause a link-time error. 58 | * 59 | * The available window API macros are: 60 | * * `GLFW_EXPOSE_NATIVE_WIN32` 61 | * * `GLFW_EXPOSE_NATIVE_COCOA` 62 | * * `GLFW_EXPOSE_NATIVE_X11` 63 | * * `GLFW_EXPOSE_NATIVE_WAYLAND` 64 | * * `GLFW_EXPOSE_NATIVE_MIR` 65 | * 66 | * The available context API macros are: 67 | * * `GLFW_EXPOSE_NATIVE_WGL` 68 | * * `GLFW_EXPOSE_NATIVE_NSGL` 69 | * * `GLFW_EXPOSE_NATIVE_GLX` 70 | * * `GLFW_EXPOSE_NATIVE_EGL` 71 | * 72 | * These macros select which of the native access functions that are declared 73 | * and which platform-specific headers to include. It is then up your (by 74 | * definition platform-specific) code to handle which of these should be 75 | * defined. 76 | */ 77 | 78 | 79 | /************************************************************************* 80 | * System headers and types 81 | *************************************************************************/ 82 | 83 | #if defined(GLFW_EXPOSE_NATIVE_WIN32) 84 | // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for 85 | // example to allow applications to correctly declare a GL_ARB_debug_output 86 | // callback) but windows.h assumes no one will define APIENTRY before it does 87 | #undef APIENTRY 88 | #include 89 | #elif defined(GLFW_EXPOSE_NATIVE_COCOA) 90 | #include 91 | #if defined(__OBJC__) 92 | #import 93 | #else 94 | typedef void* id; 95 | #endif 96 | #elif defined(GLFW_EXPOSE_NATIVE_X11) 97 | #include 98 | #include 99 | #elif defined(GLFW_EXPOSE_NATIVE_WAYLAND) 100 | #include 101 | #elif defined(GLFW_EXPOSE_NATIVE_MIR) 102 | #include 103 | #endif 104 | 105 | #if defined(GLFW_EXPOSE_NATIVE_WGL) 106 | /* WGL is declared by windows.h */ 107 | #endif 108 | #if defined(GLFW_EXPOSE_NATIVE_NSGL) 109 | /* NSGL is declared by Cocoa.h */ 110 | #endif 111 | #if defined(GLFW_EXPOSE_NATIVE_GLX) 112 | #include 113 | #endif 114 | #if defined(GLFW_EXPOSE_NATIVE_EGL) 115 | #include 116 | #endif 117 | 118 | 119 | /************************************************************************* 120 | * Functions 121 | *************************************************************************/ 122 | 123 | #if defined(GLFW_EXPOSE_NATIVE_WIN32) 124 | /*! @brief Returns the adapter device name of the specified monitor. 125 | * 126 | * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) 127 | * of the specified monitor, or `NULL` if an [error](@ref error_handling) 128 | * occurred. 129 | * 130 | * @thread_safety This function may be called from any thread. Access is not 131 | * synchronized. 132 | * 133 | * @since Added in version 3.1. 134 | * 135 | * @ingroup native 136 | */ 137 | GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); 138 | 139 | /*! @brief Returns the display device name of the specified monitor. 140 | * 141 | * @return The UTF-8 encoded display device name (for example 142 | * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an 143 | * [error](@ref error_handling) occurred. 144 | * 145 | * @thread_safety This function may be called from any thread. Access is not 146 | * synchronized. 147 | * 148 | * @since Added in version 3.1. 149 | * 150 | * @ingroup native 151 | */ 152 | GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); 153 | 154 | /*! @brief Returns the `HWND` of the specified window. 155 | * 156 | * @return The `HWND` of the specified window, or `NULL` if an 157 | * [error](@ref error_handling) occurred. 158 | * 159 | * @thread_safety This function may be called from any thread. Access is not 160 | * synchronized. 161 | * 162 | * @since Added in version 3.0. 163 | * 164 | * @ingroup native 165 | */ 166 | GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); 167 | #endif 168 | 169 | #if defined(GLFW_EXPOSE_NATIVE_WGL) 170 | /*! @brief Returns the `HGLRC` of the specified window. 171 | * 172 | * @return The `HGLRC` of the specified window, or `NULL` if an 173 | * [error](@ref error_handling) occurred. 174 | * 175 | * @thread_safety This function may be called from any thread. Access is not 176 | * synchronized. 177 | * 178 | * @since Added in version 3.0. 179 | * 180 | * @ingroup native 181 | */ 182 | GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); 183 | #endif 184 | 185 | #if defined(GLFW_EXPOSE_NATIVE_COCOA) 186 | /*! @brief Returns the `CGDirectDisplayID` of the specified monitor. 187 | * 188 | * @return The `CGDirectDisplayID` of the specified monitor, or 189 | * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. 190 | * 191 | * @thread_safety This function may be called from any thread. Access is not 192 | * synchronized. 193 | * 194 | * @since Added in version 3.1. 195 | * 196 | * @ingroup native 197 | */ 198 | GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); 199 | 200 | /*! @brief Returns the `NSWindow` of the specified window. 201 | * 202 | * @return The `NSWindow` of the specified window, or `nil` if an 203 | * [error](@ref error_handling) occurred. 204 | * 205 | * @thread_safety This function may be called from any thread. Access is not 206 | * synchronized. 207 | * 208 | * @since Added in version 3.0. 209 | * 210 | * @ingroup native 211 | */ 212 | GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); 213 | #endif 214 | 215 | #if defined(GLFW_EXPOSE_NATIVE_NSGL) 216 | /*! @brief Returns the `NSOpenGLContext` of the specified window. 217 | * 218 | * @return The `NSOpenGLContext` of the specified window, or `nil` if an 219 | * [error](@ref error_handling) occurred. 220 | * 221 | * @thread_safety This function may be called from any thread. Access is not 222 | * synchronized. 223 | * 224 | * @since Added in version 3.0. 225 | * 226 | * @ingroup native 227 | */ 228 | GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); 229 | #endif 230 | 231 | #if defined(GLFW_EXPOSE_NATIVE_X11) 232 | /*! @brief Returns the `Display` used by GLFW. 233 | * 234 | * @return The `Display` used by GLFW, or `NULL` if an 235 | * [error](@ref error_handling) occurred. 236 | * 237 | * @thread_safety This function may be called from any thread. Access is not 238 | * synchronized. 239 | * 240 | * @since Added in version 3.0. 241 | * 242 | * @ingroup native 243 | */ 244 | GLFWAPI Display* glfwGetX11Display(void); 245 | 246 | /*! @brief Returns the `RRCrtc` of the specified monitor. 247 | * 248 | * @return The `RRCrtc` of the specified monitor, or `None` if an 249 | * [error](@ref error_handling) occurred. 250 | * 251 | * @thread_safety This function may be called from any thread. Access is not 252 | * synchronized. 253 | * 254 | * @since Added in version 3.1. 255 | * 256 | * @ingroup native 257 | */ 258 | GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); 259 | 260 | /*! @brief Returns the `RROutput` of the specified monitor. 261 | * 262 | * @return The `RROutput` of the specified monitor, or `None` if an 263 | * [error](@ref error_handling) occurred. 264 | * 265 | * @thread_safety This function may be called from any thread. Access is not 266 | * synchronized. 267 | * 268 | * @since Added in version 3.1. 269 | * 270 | * @ingroup native 271 | */ 272 | GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); 273 | 274 | /*! @brief Returns the `Window` of the specified window. 275 | * 276 | * @return The `Window` of the specified window, or `None` if an 277 | * [error](@ref error_handling) occurred. 278 | * 279 | * @thread_safety This function may be called from any thread. Access is not 280 | * synchronized. 281 | * 282 | * @since Added in version 3.0. 283 | * 284 | * @ingroup native 285 | */ 286 | GLFWAPI Window glfwGetX11Window(GLFWwindow* window); 287 | #endif 288 | 289 | #if defined(GLFW_EXPOSE_NATIVE_GLX) 290 | /*! @brief Returns the `GLXContext` of the specified window. 291 | * 292 | * @return The `GLXContext` of the specified window, or `NULL` if an 293 | * [error](@ref error_handling) occurred. 294 | * 295 | * @thread_safety This function may be called from any thread. Access is not 296 | * synchronized. 297 | * 298 | * @since Added in version 3.0. 299 | * 300 | * @ingroup native 301 | */ 302 | GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); 303 | 304 | /*! @brief Returns the `GLXWindow` of the specified window. 305 | * 306 | * @return The `GLXWindow` of the specified window, or `None` if an 307 | * [error](@ref error_handling) occurred. 308 | * 309 | * @thread_safety This function may be called from any thread. Access is not 310 | * synchronized. 311 | * 312 | * @since Added in version 3.2. 313 | * 314 | * @ingroup native 315 | */ 316 | GLFWAPI GLXWindow glfwGetGLXWindow(GLFWwindow* window); 317 | #endif 318 | 319 | #if defined(GLFW_EXPOSE_NATIVE_WAYLAND) 320 | /*! @brief Returns the `struct wl_display*` used by GLFW. 321 | * 322 | * @return The `struct wl_display*` used by GLFW, or `NULL` if an 323 | * [error](@ref error_handling) occurred. 324 | * 325 | * @thread_safety This function may be called from any thread. Access is not 326 | * synchronized. 327 | * 328 | * @since Added in version 3.2. 329 | * 330 | * @ingroup native 331 | */ 332 | GLFWAPI struct wl_display* glfwGetWaylandDisplay(void); 333 | 334 | /*! @brief Returns the `struct wl_output*` of the specified monitor. 335 | * 336 | * @return The `struct wl_output*` of the specified monitor, or `NULL` if an 337 | * [error](@ref error_handling) occurred. 338 | * 339 | * @thread_safety This function may be called from any thread. Access is not 340 | * synchronized. 341 | * 342 | * @since Added in version 3.2. 343 | * 344 | * @ingroup native 345 | */ 346 | GLFWAPI struct wl_output* glfwGetWaylandMonitor(GLFWmonitor* monitor); 347 | 348 | /*! @brief Returns the main `struct wl_surface*` of the specified window. 349 | * 350 | * @return The main `struct wl_surface*` of the specified window, or `NULL` if 351 | * an [error](@ref error_handling) occurred. 352 | * 353 | * @thread_safety This function may be called from any thread. Access is not 354 | * synchronized. 355 | * 356 | * @since Added in version 3.2. 357 | * 358 | * @ingroup native 359 | */ 360 | GLFWAPI struct wl_surface* glfwGetWaylandWindow(GLFWwindow* window); 361 | #endif 362 | 363 | #if defined(GLFW_EXPOSE_NATIVE_MIR) 364 | /*! @brief Returns the `MirConnection*` used by GLFW. 365 | * 366 | * @return The `MirConnection*` used by GLFW, or `NULL` if an 367 | * [error](@ref error_handling) occurred. 368 | * 369 | * @thread_safety This function may be called from any thread. Access is not 370 | * synchronized. 371 | * 372 | * @since Added in version 3.2. 373 | * 374 | * @ingroup native 375 | */ 376 | GLFWAPI MirConnection* glfwGetMirDisplay(void); 377 | 378 | /*! @brief Returns the Mir output ID of the specified monitor. 379 | * 380 | * @return The Mir output ID of the specified monitor, or zero if an 381 | * [error](@ref error_handling) occurred. 382 | * 383 | * @thread_safety This function may be called from any thread. Access is not 384 | * synchronized. 385 | * 386 | * @since Added in version 3.2. 387 | * 388 | * @ingroup native 389 | */ 390 | GLFWAPI int glfwGetMirMonitor(GLFWmonitor* monitor); 391 | 392 | /*! @brief Returns the `MirSurface*` of the specified window. 393 | * 394 | * @return The `MirSurface*` of the specified window, or `NULL` if an 395 | * [error](@ref error_handling) occurred. 396 | * 397 | * @thread_safety This function may be called from any thread. Access is not 398 | * synchronized. 399 | * 400 | * @since Added in version 3.2. 401 | * 402 | * @ingroup native 403 | */ 404 | GLFWAPI MirSurface* glfwGetMirWindow(GLFWwindow* window); 405 | #endif 406 | 407 | #if defined(GLFW_EXPOSE_NATIVE_EGL) 408 | /*! @brief Returns the `EGLDisplay` used by GLFW. 409 | * 410 | * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an 411 | * [error](@ref error_handling) occurred. 412 | * 413 | * @thread_safety This function may be called from any thread. Access is not 414 | * synchronized. 415 | * 416 | * @since Added in version 3.0. 417 | * 418 | * @ingroup native 419 | */ 420 | GLFWAPI EGLDisplay glfwGetEGLDisplay(void); 421 | 422 | /*! @brief Returns the `EGLContext` of the specified window. 423 | * 424 | * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an 425 | * [error](@ref error_handling) occurred. 426 | * 427 | * @thread_safety This function may be called from any thread. Access is not 428 | * synchronized. 429 | * 430 | * @since Added in version 3.0. 431 | * 432 | * @ingroup native 433 | */ 434 | GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); 435 | 436 | /*! @brief Returns the `EGLSurface` of the specified window. 437 | * 438 | * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an 439 | * [error](@ref error_handling) occurred. 440 | * 441 | * @thread_safety This function may be called from any thread. Access is not 442 | * synchronized. 443 | * 444 | * @since Added in version 3.0. 445 | * 446 | * @ingroup native 447 | */ 448 | GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); 449 | #endif 450 | 451 | #ifdef __cplusplus 452 | } 453 | #endif 454 | 455 | #endif /* _glfw3_native_h_ */ 456 | 457 | -------------------------------------------------------------------------------- /src/reuse/glfw/lib-vc2010-32/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightbits/fraktal/b8760dc2db979efb91a7b001086b873dfaa22242/src/reuse/glfw/lib-vc2010-32/glfw3.lib -------------------------------------------------------------------------------- /src/reuse/glfw/lib-vc2010-64/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lightbits/fraktal/b8760dc2db979efb91a7b001086b873dfaa22242/src/reuse/glfw/lib-vc2010-64/glfw3.lib -------------------------------------------------------------------------------- /src/reuse/imgui/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2019 Omar Cornut 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/reuse/imgui/imconfig.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------- 2 | // COMPILE-TIME OPTIONS FOR DEAR IMGUI 3 | // Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure. 4 | // You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions. 5 | //----------------------------------------------------------------------------- 6 | // A) You may edit imconfig.h (and not overwrite it when updating imgui, or maintain a patch/branch with your modifications to imconfig.h) 7 | // B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h" 8 | // If you do so you need to make sure that configuration settings are defined consistently _everywhere_ dear imgui is used, which include 9 | // the imgui*.cpp files but also _any_ of your code that uses imgui. This is because some compile-time options have an affect on data structures. 10 | // Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts. 11 | // Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using. 12 | //----------------------------------------------------------------------------- 13 | 14 | #pragma once 15 | 16 | //---- Define assertion handler. Defaults to calling assert(). 17 | //#define IM_ASSERT(_EXPR) MyAssert(_EXPR) 18 | //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts 19 | 20 | //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows. 21 | //#define IMGUI_API __declspec( dllexport ) 22 | //#define IMGUI_API __declspec( dllimport ) 23 | 24 | //---- Don't define obsolete functions/enums names. Consider enabling from time to time after updating to avoid using soon-to-be obsolete function/names. 25 | //#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS 26 | 27 | //---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty) 28 | //---- It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp. 29 | //#define IMGUI_DISABLE_DEMO_WINDOWS 30 | 31 | //---- Don't implement some functions to reduce linkage requirements. 32 | //#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc. 33 | //#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow. 34 | //#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function. 35 | //#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf. 36 | //#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h. 37 | //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). 38 | 39 | //---- Include imgui_user.h at the end of imgui.h as a convenience 40 | //#define IMGUI_INCLUDE_IMGUI_USER_H 41 | 42 | //---- Pack colors to BGRA8 instead of RGBA8 (to avoid converting from one to another) 43 | //#define IMGUI_USE_BGRA_PACKED_COLOR 44 | 45 | //---- Avoid multiple STB libraries implementations, or redefine path/filenames to prioritize another version 46 | // By default the embedded implementations are declared static and not available outside of imgui cpp files. 47 | //#define IMGUI_STB_TRUETYPE_FILENAME "my_folder/stb_truetype.h" 48 | //#define IMGUI_STB_RECT_PACK_FILENAME "my_folder/stb_rect_pack.h" 49 | //#define IMGUI_DISABLE_STB_TRUETYPE_IMPLEMENTATION 50 | //#define IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION 51 | 52 | //---- Define constructor and implicit cast operators to convert back<>forth between your math types and ImVec2/ImVec4. 53 | // This will be inlined as part of ImVec2 and ImVec4 class declarations. 54 | /* 55 | #define IM_VEC2_CLASS_EXTRA \ 56 | ImVec2(const MyVec2& f) { x = f.x; y = f.y; } \ 57 | operator MyVec2() const { return MyVec2(x,y); } 58 | 59 | #define IM_VEC4_CLASS_EXTRA \ 60 | ImVec4(const MyVec4& f) { x = f.x; y = f.y; z = f.z; w = f.w; } \ 61 | operator MyVec4() const { return MyVec4(x,y,z,w); } 62 | */ 63 | 64 | //---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it. 65 | //#define ImDrawIdx unsigned int 66 | 67 | //---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files. 68 | /* 69 | namespace ImGui 70 | { 71 | void MyFunction(const char* name, const MyMatrix44& v); 72 | } 73 | */ 74 | -------------------------------------------------------------------------------- /src/reuse/imgui/imgui_impl_glfw.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Binding for GLFW 2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) 3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) 4 | // (Requires: GLFW 3.1+) 5 | 6 | // Implemented features: 7 | // [X] Platform: Clipboard support. 8 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 9 | // [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. 10 | // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). 11 | 12 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 13 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 14 | // https://github.com/ocornut/imgui 15 | 16 | // CHANGELOG 17 | // (minor and older changes stripped away, please see git history for details) 18 | // 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window. 19 | // 2018-11-07: Inputs: When installing our GLFW callbacks, we save user's previously installed ones - if any - and chain call them. 20 | // 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls. 21 | // 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor. 22 | // 2018-06-08: Misc: Extracted imgui_impl_glfw.cpp/.h away from the old combined GLFW+OpenGL/Vulkan examples. 23 | // 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag. 24 | // 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value, passed to glfwSetCursor()). 25 | // 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves. 26 | // 2018-02-06: Inputs: Added mapping for ImGuiKey_Space. 27 | // 2018-01-25: Inputs: Added gamepad support if ImGuiConfigFlags_NavEnableGamepad is set. 28 | // 2018-01-25: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set). 29 | // 2018-01-20: Inputs: Added Horizontal Mouse Wheel support. 30 | // 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert. 31 | // 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1). 32 | // 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers. 33 | 34 | #include "imgui.h" 35 | #include "imgui_impl_glfw.h" 36 | 37 | // GLFW 38 | #include 39 | #ifdef _WIN32 40 | #undef APIENTRY 41 | #define GLFW_EXPOSE_NATIVE_WIN32 42 | #include // for glfwGetWin32Window 43 | #endif 44 | #define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ GLFW_FLOATING 45 | #define GLFW_HAS_WINDOW_HOVERED (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ GLFW_HOVERED 46 | #define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwSetWindowOpacity 47 | #define GLFW_HAS_PER_MONITOR_DPI (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ glfwGetMonitorContentScale 48 | #define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ glfwCreateWindowSurface 49 | 50 | // Data 51 | enum GlfwClientApi 52 | { 53 | GlfwClientApi_Unknown, 54 | GlfwClientApi_OpenGL, 55 | GlfwClientApi_Vulkan 56 | }; 57 | static GLFWwindow* g_Window = NULL; 58 | static GlfwClientApi g_ClientApi = GlfwClientApi_Unknown; 59 | static double g_Time = 0.0; 60 | static bool g_MouseJustPressed[5] = { false, false, false, false, false }; 61 | static GLFWcursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = { 0 }; 62 | 63 | // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. 64 | static GLFWmousebuttonfun g_PrevUserCallbackMousebutton = NULL; 65 | static GLFWscrollfun g_PrevUserCallbackScroll = NULL; 66 | static GLFWkeyfun g_PrevUserCallbackKey = NULL; 67 | static GLFWcharfun g_PrevUserCallbackChar = NULL; 68 | 69 | static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data) 70 | { 71 | return glfwGetClipboardString((GLFWwindow*)user_data); 72 | } 73 | 74 | static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text) 75 | { 76 | glfwSetClipboardString((GLFWwindow*)user_data, text); 77 | } 78 | 79 | void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods) 80 | { 81 | if (g_PrevUserCallbackMousebutton != NULL) 82 | g_PrevUserCallbackMousebutton(window, button, action, mods); 83 | 84 | if (action == GLFW_PRESS && button >= 0 && button < IM_ARRAYSIZE(g_MouseJustPressed)) 85 | g_MouseJustPressed[button] = true; 86 | } 87 | 88 | void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset) 89 | { 90 | if (g_PrevUserCallbackScroll != NULL) 91 | g_PrevUserCallbackScroll(window, xoffset, yoffset); 92 | 93 | ImGuiIO& io = ImGui::GetIO(); 94 | io.MouseWheelH += (float)xoffset; 95 | io.MouseWheel += (float)yoffset; 96 | } 97 | 98 | void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) 99 | { 100 | if (g_PrevUserCallbackKey != NULL) 101 | g_PrevUserCallbackKey(window, key, scancode, action, mods); 102 | 103 | ImGuiIO& io = ImGui::GetIO(); 104 | if (action == GLFW_PRESS) 105 | io.KeysDown[key] = true; 106 | if (action == GLFW_RELEASE) 107 | io.KeysDown[key] = false; 108 | 109 | // Modifiers are not reliable across systems 110 | io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL]; 111 | io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT]; 112 | io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT]; 113 | io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER]; 114 | } 115 | 116 | void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c) 117 | { 118 | if (g_PrevUserCallbackChar != NULL) 119 | g_PrevUserCallbackChar(window, c); 120 | 121 | ImGuiIO& io = ImGui::GetIO(); 122 | if (c > 0 && c < 0x10000) 123 | io.AddInputCharacter((unsigned short)c); 124 | } 125 | 126 | static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, GlfwClientApi client_api) 127 | { 128 | g_Window = window; 129 | g_Time = 0.0; 130 | 131 | // Setup back-end capabilities flags 132 | ImGuiIO& io = ImGui::GetIO(); 133 | io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional) 134 | io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; // We can honor io.WantSetMousePos requests (optional, rarely used) 135 | io.BackendPlatformName = "imgui_impl_glfw"; 136 | 137 | // Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array. 138 | io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB; 139 | io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT; 140 | io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT; 141 | io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP; 142 | io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN; 143 | io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP; 144 | io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN; 145 | io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME; 146 | io.KeyMap[ImGuiKey_End] = GLFW_KEY_END; 147 | io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT; 148 | io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE; 149 | io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE; 150 | io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE; 151 | io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER; 152 | io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE; 153 | io.KeyMap[ImGuiKey_A] = GLFW_KEY_A; 154 | io.KeyMap[ImGuiKey_C] = GLFW_KEY_C; 155 | io.KeyMap[ImGuiKey_V] = GLFW_KEY_V; 156 | io.KeyMap[ImGuiKey_X] = GLFW_KEY_X; 157 | io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y; 158 | io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z; 159 | 160 | io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText; 161 | io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText; 162 | io.ClipboardUserData = g_Window; 163 | #if defined(_WIN32) 164 | io.ImeWindowHandle = (void*)glfwGetWin32Window(g_Window); 165 | #endif 166 | 167 | g_MouseCursors[ImGuiMouseCursor_Arrow] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); 168 | g_MouseCursors[ImGuiMouseCursor_TextInput] = glfwCreateStandardCursor(GLFW_IBEAM_CURSOR); 169 | g_MouseCursors[ImGuiMouseCursor_ResizeAll] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. 170 | g_MouseCursors[ImGuiMouseCursor_ResizeNS] = glfwCreateStandardCursor(GLFW_VRESIZE_CURSOR); 171 | g_MouseCursors[ImGuiMouseCursor_ResizeEW] = glfwCreateStandardCursor(GLFW_HRESIZE_CURSOR); 172 | g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. 173 | g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = glfwCreateStandardCursor(GLFW_ARROW_CURSOR); // FIXME: GLFW doesn't have this. 174 | g_MouseCursors[ImGuiMouseCursor_Hand] = glfwCreateStandardCursor(GLFW_HAND_CURSOR); 175 | 176 | // Chain GLFW callbacks: our callbacks will call the user's previously installed callbacks, if any. 177 | g_PrevUserCallbackMousebutton = NULL; 178 | g_PrevUserCallbackScroll = NULL; 179 | g_PrevUserCallbackKey = NULL; 180 | g_PrevUserCallbackChar = NULL; 181 | if (install_callbacks) 182 | { 183 | g_PrevUserCallbackMousebutton = glfwSetMouseButtonCallback(window, ImGui_ImplGlfw_MouseButtonCallback); 184 | g_PrevUserCallbackScroll = glfwSetScrollCallback(window, ImGui_ImplGlfw_ScrollCallback); 185 | g_PrevUserCallbackKey = glfwSetKeyCallback(window, ImGui_ImplGlfw_KeyCallback); 186 | g_PrevUserCallbackChar = glfwSetCharCallback(window, ImGui_ImplGlfw_CharCallback); 187 | } 188 | 189 | g_ClientApi = client_api; 190 | return true; 191 | } 192 | 193 | bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks) 194 | { 195 | return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_OpenGL); 196 | } 197 | 198 | bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks) 199 | { 200 | return ImGui_ImplGlfw_Init(window, install_callbacks, GlfwClientApi_Vulkan); 201 | } 202 | 203 | void ImGui_ImplGlfw_Shutdown() 204 | { 205 | for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++) 206 | { 207 | glfwDestroyCursor(g_MouseCursors[cursor_n]); 208 | g_MouseCursors[cursor_n] = NULL; 209 | } 210 | g_ClientApi = GlfwClientApi_Unknown; 211 | } 212 | 213 | static void ImGui_ImplGlfw_UpdateMousePosAndButtons() 214 | { 215 | // Update buttons 216 | ImGuiIO& io = ImGui::GetIO(); 217 | for (int i = 0; i < IM_ARRAYSIZE(io.MouseDown); i++) 218 | { 219 | // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame. 220 | io.MouseDown[i] = g_MouseJustPressed[i] || glfwGetMouseButton(g_Window, i) != 0; 221 | g_MouseJustPressed[i] = false; 222 | } 223 | 224 | // Update mouse position 225 | const ImVec2 mouse_pos_backup = io.MousePos; 226 | io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX); 227 | #ifdef __EMSCRIPTEN__ 228 | const bool focused = true; // Emscripten 229 | #else 230 | const bool focused = glfwGetWindowAttrib(g_Window, GLFW_FOCUSED) != 0; 231 | #endif 232 | if (focused) 233 | { 234 | if (io.WantSetMousePos) 235 | { 236 | glfwSetCursorPos(g_Window, (double)mouse_pos_backup.x, (double)mouse_pos_backup.y); 237 | } 238 | else 239 | { 240 | double mouse_x, mouse_y; 241 | glfwGetCursorPos(g_Window, &mouse_x, &mouse_y); 242 | io.MousePos = ImVec2((float)mouse_x, (float)mouse_y); 243 | } 244 | } 245 | } 246 | 247 | static void ImGui_ImplGlfw_UpdateMouseCursor() 248 | { 249 | ImGuiIO& io = ImGui::GetIO(); 250 | if ((io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange) || glfwGetInputMode(g_Window, GLFW_CURSOR) == GLFW_CURSOR_DISABLED) 251 | return; 252 | 253 | ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor(); 254 | if (imgui_cursor == ImGuiMouseCursor_None || io.MouseDrawCursor) 255 | { 256 | // Hide OS mouse cursor if imgui is drawing it or if it wants no cursor 257 | glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN); 258 | } 259 | else 260 | { 261 | // Show OS mouse cursor 262 | // FIXME-PLATFORM: Unfocused windows seems to fail changing the mouse cursor with GLFW 3.2, but 3.3 works here. 263 | glfwSetCursor(g_Window, g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]); 264 | glfwSetInputMode(g_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); 265 | } 266 | } 267 | 268 | void ImGui_ImplGlfw_NewFrame() 269 | { 270 | ImGuiIO& io = ImGui::GetIO(); 271 | IM_ASSERT(io.Fonts->IsBuilt() && "Font atlas not built! It is generally built by the renderer back-end. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame()."); 272 | 273 | // Setup display size (every frame to accommodate for window resizing) 274 | int w, h; 275 | int display_w, display_h; 276 | glfwGetWindowSize(g_Window, &w, &h); 277 | glfwGetFramebufferSize(g_Window, &display_w, &display_h); 278 | io.DisplaySize = ImVec2((float)w, (float)h); 279 | io.DisplayFramebufferScale = ImVec2(w > 0 ? ((float)display_w / w) : 0, h > 0 ? ((float)display_h / h) : 0); 280 | 281 | // Setup time step 282 | double current_time = glfwGetTime(); 283 | io.DeltaTime = g_Time > 0.0 ? (float)(current_time - g_Time) : (float)(1.0f/60.0f); 284 | g_Time = current_time; 285 | 286 | ImGui_ImplGlfw_UpdateMousePosAndButtons(); 287 | ImGui_ImplGlfw_UpdateMouseCursor(); 288 | 289 | // Gamepad navigation mapping [BETA] 290 | memset(io.NavInputs, 0, sizeof(io.NavInputs)); 291 | if (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) 292 | { 293 | // Update gamepad inputs 294 | #define MAP_BUTTON(NAV_NO, BUTTON_NO) { if (buttons_count > BUTTON_NO && buttons[BUTTON_NO] == GLFW_PRESS) io.NavInputs[NAV_NO] = 1.0f; } 295 | #define MAP_ANALOG(NAV_NO, AXIS_NO, V0, V1) { float v = (axes_count > AXIS_NO) ? axes[AXIS_NO] : V0; v = (v - V0) / (V1 - V0); if (v > 1.0f) v = 1.0f; if (io.NavInputs[NAV_NO] < v) io.NavInputs[NAV_NO] = v; } 296 | int axes_count = 0, buttons_count = 0; 297 | const float* axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1, &axes_count); 298 | const unsigned char* buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1, &buttons_count); 299 | MAP_BUTTON(ImGuiNavInput_Activate, 0); // Cross / A 300 | MAP_BUTTON(ImGuiNavInput_Cancel, 1); // Circle / B 301 | MAP_BUTTON(ImGuiNavInput_Menu, 2); // Square / X 302 | MAP_BUTTON(ImGuiNavInput_Input, 3); // Triangle / Y 303 | MAP_BUTTON(ImGuiNavInput_DpadLeft, 13); // D-Pad Left 304 | MAP_BUTTON(ImGuiNavInput_DpadRight, 11); // D-Pad Right 305 | MAP_BUTTON(ImGuiNavInput_DpadUp, 10); // D-Pad Up 306 | MAP_BUTTON(ImGuiNavInput_DpadDown, 12); // D-Pad Down 307 | MAP_BUTTON(ImGuiNavInput_FocusPrev, 4); // L1 / LB 308 | MAP_BUTTON(ImGuiNavInput_FocusNext, 5); // R1 / RB 309 | MAP_BUTTON(ImGuiNavInput_TweakSlow, 4); // L1 / LB 310 | MAP_BUTTON(ImGuiNavInput_TweakFast, 5); // R1 / RB 311 | MAP_ANALOG(ImGuiNavInput_LStickLeft, 0, -0.3f, -0.9f); 312 | MAP_ANALOG(ImGuiNavInput_LStickRight,0, +0.3f, +0.9f); 313 | MAP_ANALOG(ImGuiNavInput_LStickUp, 1, +0.3f, +0.9f); 314 | MAP_ANALOG(ImGuiNavInput_LStickDown, 1, -0.3f, -0.9f); 315 | #undef MAP_BUTTON 316 | #undef MAP_ANALOG 317 | if (axes_count > 0 && buttons_count > 0) 318 | io.BackendFlags |= ImGuiBackendFlags_HasGamepad; 319 | else 320 | io.BackendFlags &= ~ImGuiBackendFlags_HasGamepad; 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /src/reuse/imgui/imgui_impl_glfw.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Platform Binding for GLFW 2 | // This needs to be used along with a Renderer (e.g. OpenGL3, Vulkan..) 3 | // (Info: GLFW is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan graphics context creation, etc.) 4 | 5 | // Implemented features: 6 | // [X] Platform: Clipboard support. 7 | // [X] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. 8 | // [x] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: 3 cursors types are missing from GLFW. 9 | // [X] Platform: Keyboard arrays indexed using GLFW_KEY_* codes, e.g. ImGui::IsKeyPressed(GLFW_KEY_SPACE). 10 | 11 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 12 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 13 | // https://github.com/ocornut/imgui 14 | 15 | // About GLSL version: 16 | // The 'glsl_version' initialization parameter defaults to "#version 150" if NULL. 17 | // Only override if your GL version doesn't handle this GLSL version. Keep NULL if unsure! 18 | 19 | #pragma once 20 | 21 | struct GLFWwindow; 22 | 23 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow* window, bool install_callbacks); 24 | IMGUI_IMPL_API bool ImGui_ImplGlfw_InitForVulkan(GLFWwindow* window, bool install_callbacks); 25 | IMGUI_IMPL_API void ImGui_ImplGlfw_Shutdown(); 26 | IMGUI_IMPL_API void ImGui_ImplGlfw_NewFrame(); 27 | 28 | // InitXXX function with 'install_callbacks=true': install GLFW callbacks. They will call user's previously installed callbacks, if any. 29 | // InitXXX function with 'install_callbacks=false': do not install GLFW callbacks. You will need to call them yourself from your own GLFW callbacks. 30 | IMGUI_IMPL_API void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods); 31 | IMGUI_IMPL_API void ImGui_ImplGlfw_ScrollCallback(GLFWwindow* window, double xoffset, double yoffset); 32 | IMGUI_IMPL_API void ImGui_ImplGlfw_KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); 33 | IMGUI_IMPL_API void ImGui_ImplGlfw_CharCallback(GLFWwindow* window, unsigned int c); 34 | -------------------------------------------------------------------------------- /src/reuse/imgui/imgui_impl_opengl3.h: -------------------------------------------------------------------------------- 1 | // dear imgui: Renderer for OpenGL3 / OpenGL ES2 / OpenGL ES3 (modern OpenGL with shaders / programmatic pipeline) 2 | // This needs to be used along with a Platform Binding (e.g. GLFW, SDL, Win32, custom..) 3 | // (Note: We are using GL3W as a helper library to access OpenGL functions since there is no standard header to access modern OpenGL functions easily. Alternatives are GLEW, Glad, etc..) 4 | 5 | // Implemented features: 6 | // [X] Renderer: User texture binding. Use 'GLuint' OpenGL texture identifier as void*/ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. 7 | 8 | // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. 9 | // If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp. 10 | // https://github.com/ocornut/imgui 11 | 12 | // About OpenGL function loaders: 13 | // About OpenGL function loaders: modern OpenGL doesn't have a standard header file and requires individual function pointers to be loaded manually. 14 | // Helper libraries are often used for this purpose! Here we are supporting a few common ones: gl3w, glew, glad. 15 | // You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own. 16 | 17 | // About GLSL version: 18 | // The 'glsl_version' initialization parameter should be NULL (default) or a "#version XXX" string. 19 | // On computer platform the GLSL version default to "#version 130". On OpenGL ES 3 platform it defaults to "#version 300 es" 20 | // Only override if your GL version doesn't handle this GLSL version. See GLSL version table at the top of imgui_impl_opengl3.cpp. 21 | 22 | #pragma once 23 | 24 | // Set default OpenGL loader to be gl3w 25 | #if !defined(IMGUI_IMPL_OPENGL_LOADER_GL3W) \ 26 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLEW) \ 27 | && !defined(IMGUI_IMPL_OPENGL_LOADER_GLAD) \ 28 | && !defined(IMGUI_IMPL_OPENGL_LOADER_CUSTOM) 29 | #define IMGUI_IMPL_OPENGL_LOADER_GL3W 30 | #endif 31 | 32 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = NULL); 33 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown(); 34 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame(); 35 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); 36 | 37 | // Called by Init/NewFrame/Shutdown 38 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateFontsTexture(); 39 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyFontsTexture(); 40 | IMGUI_IMPL_API bool ImGui_ImplOpenGL3_CreateDeviceObjects(); 41 | IMGUI_IMPL_API void ImGui_ImplOpenGL3_DestroyDeviceObjects(); 42 | -------------------------------------------------------------------------------- /src/reuse/imgui_extensions.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace ImGui 4 | { 5 | // Modification of DragScalarN to support per-component speeds 6 | bool DragScalarN(const char* label, ImGuiDataType data_type, void* v, int components, float* v_speed, const void* v_min, const void* v_max, const char* format, float power) 7 | { 8 | ImGuiWindow* window = GetCurrentWindow(); 9 | if (window->SkipItems) 10 | return false; 11 | 12 | ImGuiContext& g = *GImGui; 13 | bool value_changed = false; 14 | BeginGroup(); 15 | PushID(label); 16 | PushMultiItemsWidths(components); 17 | size_t type_size = GDataTypeInfo[data_type].Size; 18 | for (int i = 0; i < components; i++) 19 | { 20 | PushID(i); 21 | value_changed |= DragScalar("", data_type, v, v_speed[i], v_min, v_max, format, power); 22 | SameLine(0, g.Style.ItemInnerSpacing.x); 23 | PopID(); 24 | PopItemWidth(); 25 | v = (void*)((char*)v + type_size); 26 | } 27 | PopID(); 28 | 29 | TextEx(label, FindRenderedTextEnd(label)); 30 | EndGroup(); 31 | return value_changed; 32 | } 33 | 34 | // v_speed = NULL -> use 1.0f 35 | bool DragFloat3(const char* label, float v[3], float* v_speed = NULL, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f) 36 | { 37 | if (v_speed) 38 | return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, power); 39 | else 40 | return DragScalarN(label, ImGuiDataType_Float, v, 3, 1.0f, &v_min, &v_max, format, power); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/reuse/jsmn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2010 Serge Zaitsev 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | #ifndef JSMN_H 25 | #define JSMN_H 26 | 27 | #include 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #ifdef JSMN_STATIC 34 | #define JSMN_API static 35 | #else 36 | #define JSMN_API extern 37 | #endif 38 | 39 | /** 40 | * JSON type identifier. Basic types are: 41 | * o Object 42 | * o Array 43 | * o String 44 | * o Other primitive: number, boolean (true/false) or null 45 | */ 46 | typedef enum { 47 | JSMN_UNDEFINED = 0, 48 | JSMN_OBJECT = 1, 49 | JSMN_ARRAY = 2, 50 | JSMN_STRING = 3, 51 | JSMN_PRIMITIVE = 4 52 | } jsmntype_t; 53 | 54 | enum jsmnerr { 55 | /* Not enough tokens were provided */ 56 | JSMN_ERROR_NOMEM = -1, 57 | /* Invalid character inside JSON string */ 58 | JSMN_ERROR_INVAL = -2, 59 | /* The string is not a full JSON packet, more bytes expected */ 60 | JSMN_ERROR_PART = -3 61 | }; 62 | 63 | /** 64 | * JSON token description. 65 | * type type (object, array, string etc.) 66 | * start start position in JSON data string 67 | * end end position in JSON data string 68 | */ 69 | typedef struct { 70 | jsmntype_t type; 71 | int start; 72 | int end; 73 | int size; 74 | #ifdef JSMN_PARENT_LINKS 75 | int parent; 76 | #endif 77 | } jsmntok_t; 78 | 79 | /** 80 | * JSON parser. Contains an array of token blocks available. Also stores 81 | * the string being parsed now and current position in that string. 82 | */ 83 | typedef struct { 84 | unsigned int pos; /* offset in the JSON string */ 85 | unsigned int toknext; /* next token to allocate */ 86 | int toksuper; /* superior token node, e.g. parent object or array */ 87 | } jsmn_parser; 88 | 89 | /** 90 | * Create JSON parser over an array of tokens 91 | */ 92 | JSMN_API void jsmn_init(jsmn_parser *parser); 93 | 94 | /** 95 | * Run JSON parser. It parses a JSON data string into and array of tokens, each 96 | * describing 97 | * a single JSON object. 98 | */ 99 | JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, 100 | jsmntok_t *tokens, const unsigned int num_tokens); 101 | 102 | #ifndef JSMN_HEADER 103 | /** 104 | * Allocates a fresh unused token from the token pool. 105 | */ 106 | static jsmntok_t *jsmn_alloc_token(jsmn_parser *parser, jsmntok_t *tokens, 107 | const size_t num_tokens) { 108 | jsmntok_t *tok; 109 | if (parser->toknext >= num_tokens) { 110 | return NULL; 111 | } 112 | tok = &tokens[parser->toknext++]; 113 | tok->start = tok->end = -1; 114 | tok->size = 0; 115 | #ifdef JSMN_PARENT_LINKS 116 | tok->parent = -1; 117 | #endif 118 | return tok; 119 | } 120 | 121 | /** 122 | * Fills token type and boundaries. 123 | */ 124 | static void jsmn_fill_token(jsmntok_t *token, const jsmntype_t type, 125 | const int start, const int end) { 126 | token->type = type; 127 | token->start = start; 128 | token->end = end; 129 | token->size = 0; 130 | } 131 | 132 | /** 133 | * Fills next available token with JSON primitive. 134 | */ 135 | static int jsmn_parse_primitive(jsmn_parser *parser, const char *js, 136 | const size_t len, jsmntok_t *tokens, 137 | const size_t num_tokens) { 138 | jsmntok_t *token; 139 | int start; 140 | 141 | start = parser->pos; 142 | 143 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 144 | switch (js[parser->pos]) { 145 | #ifndef JSMN_STRICT 146 | /* In strict mode primitive must be followed by "," or "}" or "]" */ 147 | case ':': 148 | #endif 149 | case '\t': 150 | case '\r': 151 | case '\n': 152 | case ' ': 153 | case ',': 154 | case ']': 155 | case '}': 156 | goto found; 157 | default: 158 | /* to quiet a warning from gcc*/ 159 | break; 160 | } 161 | if (js[parser->pos] < 32 || js[parser->pos] >= 127) { 162 | parser->pos = start; 163 | return JSMN_ERROR_INVAL; 164 | } 165 | } 166 | #ifdef JSMN_STRICT 167 | /* In strict mode primitive must be followed by a comma/object/array */ 168 | parser->pos = start; 169 | return JSMN_ERROR_PART; 170 | #endif 171 | 172 | found: 173 | if (tokens == NULL) { 174 | parser->pos--; 175 | return 0; 176 | } 177 | token = jsmn_alloc_token(parser, tokens, num_tokens); 178 | if (token == NULL) { 179 | parser->pos = start; 180 | return JSMN_ERROR_NOMEM; 181 | } 182 | jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos); 183 | #ifdef JSMN_PARENT_LINKS 184 | token->parent = parser->toksuper; 185 | #endif 186 | parser->pos--; 187 | return 0; 188 | } 189 | 190 | /** 191 | * Fills next token with JSON string. 192 | */ 193 | static int jsmn_parse_string(jsmn_parser *parser, const char *js, 194 | const size_t len, jsmntok_t *tokens, 195 | const size_t num_tokens) { 196 | jsmntok_t *token; 197 | 198 | int start = parser->pos; 199 | 200 | parser->pos++; 201 | 202 | /* Skip starting quote */ 203 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 204 | char c = js[parser->pos]; 205 | 206 | /* Quote: end of string */ 207 | if (c == '\"') { 208 | if (tokens == NULL) { 209 | return 0; 210 | } 211 | token = jsmn_alloc_token(parser, tokens, num_tokens); 212 | if (token == NULL) { 213 | parser->pos = start; 214 | return JSMN_ERROR_NOMEM; 215 | } 216 | jsmn_fill_token(token, JSMN_STRING, start + 1, parser->pos); 217 | #ifdef JSMN_PARENT_LINKS 218 | token->parent = parser->toksuper; 219 | #endif 220 | return 0; 221 | } 222 | 223 | /* Backslash: Quoted symbol expected */ 224 | if (c == '\\' && parser->pos + 1 < len) { 225 | int i; 226 | parser->pos++; 227 | switch (js[parser->pos]) { 228 | /* Allowed escaped symbols */ 229 | case '\"': 230 | case '/': 231 | case '\\': 232 | case 'b': 233 | case 'f': 234 | case 'r': 235 | case 'n': 236 | case 't': 237 | break; 238 | /* Allows escaped symbol \uXXXX */ 239 | case 'u': 240 | parser->pos++; 241 | for (i = 0; i < 4 && parser->pos < len && js[parser->pos] != '\0'; 242 | i++) { 243 | /* If it isn't a hex character we have an error */ 244 | if (!((js[parser->pos] >= 48 && js[parser->pos] <= 57) || /* 0-9 */ 245 | (js[parser->pos] >= 65 && js[parser->pos] <= 70) || /* A-F */ 246 | (js[parser->pos] >= 97 && js[parser->pos] <= 102))) { /* a-f */ 247 | parser->pos = start; 248 | return JSMN_ERROR_INVAL; 249 | } 250 | parser->pos++; 251 | } 252 | parser->pos--; 253 | break; 254 | /* Unexpected symbol */ 255 | default: 256 | parser->pos = start; 257 | return JSMN_ERROR_INVAL; 258 | } 259 | } 260 | } 261 | parser->pos = start; 262 | return JSMN_ERROR_PART; 263 | } 264 | 265 | /** 266 | * Parse JSON string and fill tokens. 267 | */ 268 | JSMN_API int jsmn_parse(jsmn_parser *parser, const char *js, const size_t len, 269 | jsmntok_t *tokens, const unsigned int num_tokens) { 270 | int r; 271 | int i; 272 | jsmntok_t *token; 273 | int count = parser->toknext; 274 | 275 | for (; parser->pos < len && js[parser->pos] != '\0'; parser->pos++) { 276 | char c; 277 | jsmntype_t type; 278 | 279 | c = js[parser->pos]; 280 | switch (c) { 281 | case '{': 282 | case '[': 283 | count++; 284 | if (tokens == NULL) { 285 | break; 286 | } 287 | token = jsmn_alloc_token(parser, tokens, num_tokens); 288 | if (token == NULL) { 289 | return JSMN_ERROR_NOMEM; 290 | } 291 | if (parser->toksuper != -1) { 292 | jsmntok_t *t = &tokens[parser->toksuper]; 293 | #ifdef JSMN_STRICT 294 | /* In strict mode an object or array can't become a key */ 295 | if (t->type == JSMN_OBJECT) { 296 | return JSMN_ERROR_INVAL; 297 | } 298 | #endif 299 | t->size++; 300 | #ifdef JSMN_PARENT_LINKS 301 | token->parent = parser->toksuper; 302 | #endif 303 | } 304 | token->type = (c == '{' ? JSMN_OBJECT : JSMN_ARRAY); 305 | token->start = parser->pos; 306 | parser->toksuper = parser->toknext - 1; 307 | break; 308 | case '}': 309 | case ']': 310 | if (tokens == NULL) { 311 | break; 312 | } 313 | type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY); 314 | #ifdef JSMN_PARENT_LINKS 315 | if (parser->toknext < 1) { 316 | return JSMN_ERROR_INVAL; 317 | } 318 | token = &tokens[parser->toknext - 1]; 319 | for (;;) { 320 | if (token->start != -1 && token->end == -1) { 321 | if (token->type != type) { 322 | return JSMN_ERROR_INVAL; 323 | } 324 | token->end = parser->pos + 1; 325 | parser->toksuper = token->parent; 326 | break; 327 | } 328 | if (token->parent == -1) { 329 | if (token->type != type || parser->toksuper == -1) { 330 | return JSMN_ERROR_INVAL; 331 | } 332 | break; 333 | } 334 | token = &tokens[token->parent]; 335 | } 336 | #else 337 | for (i = parser->toknext - 1; i >= 0; i--) { 338 | token = &tokens[i]; 339 | if (token->start != -1 && token->end == -1) { 340 | if (token->type != type) { 341 | return JSMN_ERROR_INVAL; 342 | } 343 | parser->toksuper = -1; 344 | token->end = parser->pos + 1; 345 | break; 346 | } 347 | } 348 | /* Error if unmatched closing bracket */ 349 | if (i == -1) { 350 | return JSMN_ERROR_INVAL; 351 | } 352 | for (; i >= 0; i--) { 353 | token = &tokens[i]; 354 | if (token->start != -1 && token->end == -1) { 355 | parser->toksuper = i; 356 | break; 357 | } 358 | } 359 | #endif 360 | break; 361 | case '\"': 362 | r = jsmn_parse_string(parser, js, len, tokens, num_tokens); 363 | if (r < 0) { 364 | return r; 365 | } 366 | count++; 367 | if (parser->toksuper != -1 && tokens != NULL) { 368 | tokens[parser->toksuper].size++; 369 | } 370 | break; 371 | case '\t': 372 | case '\r': 373 | case '\n': 374 | case ' ': 375 | break; 376 | case ':': 377 | parser->toksuper = parser->toknext - 1; 378 | break; 379 | case ',': 380 | if (tokens != NULL && parser->toksuper != -1 && 381 | tokens[parser->toksuper].type != JSMN_ARRAY && 382 | tokens[parser->toksuper].type != JSMN_OBJECT) { 383 | #ifdef JSMN_PARENT_LINKS 384 | parser->toksuper = tokens[parser->toksuper].parent; 385 | #else 386 | for (i = parser->toknext - 1; i >= 0; i--) { 387 | if (tokens[i].type == JSMN_ARRAY || tokens[i].type == JSMN_OBJECT) { 388 | if (tokens[i].start != -1 && tokens[i].end == -1) { 389 | parser->toksuper = i; 390 | break; 391 | } 392 | } 393 | } 394 | #endif 395 | } 396 | break; 397 | #ifdef JSMN_STRICT 398 | /* In strict mode primitives are: numbers and booleans */ 399 | case '-': 400 | case '0': 401 | case '1': 402 | case '2': 403 | case '3': 404 | case '4': 405 | case '5': 406 | case '6': 407 | case '7': 408 | case '8': 409 | case '9': 410 | case 't': 411 | case 'f': 412 | case 'n': 413 | /* And they must not be keys of the object */ 414 | if (tokens != NULL && parser->toksuper != -1) { 415 | const jsmntok_t *t = &tokens[parser->toksuper]; 416 | if (t->type == JSMN_OBJECT || 417 | (t->type == JSMN_STRING && t->size != 0)) { 418 | return JSMN_ERROR_INVAL; 419 | } 420 | } 421 | #else 422 | /* In non-strict mode every unquoted value is a primitive */ 423 | default: 424 | #endif 425 | r = jsmn_parse_primitive(parser, js, len, tokens, num_tokens); 426 | if (r < 0) { 427 | return r; 428 | } 429 | count++; 430 | if (parser->toksuper != -1 && tokens != NULL) { 431 | tokens[parser->toksuper].size++; 432 | } 433 | break; 434 | 435 | #ifdef JSMN_STRICT 436 | /* Unexpected char in strict mode */ 437 | default: 438 | return JSMN_ERROR_INVAL; 439 | #endif 440 | } 441 | } 442 | 443 | if (tokens != NULL) { 444 | for (i = parser->toknext - 1; i >= 0; i--) { 445 | /* Unmatched opened object or array */ 446 | if (tokens[i].start != -1 && tokens[i].end == -1) { 447 | return JSMN_ERROR_PART; 448 | } 449 | } 450 | } 451 | 452 | return count; 453 | } 454 | 455 | /** 456 | * Creates a new parser based over a given buffer with an array of tokens 457 | * available. 458 | */ 459 | JSMN_API void jsmn_init(jsmn_parser *parser) { 460 | parser->pos = 0; 461 | parser->toknext = 0; 462 | parser->toksuper = -1; 463 | } 464 | 465 | #endif /* JSMN_HEADER */ 466 | 467 | #ifdef __cplusplus 468 | } 469 | #endif 470 | 471 | #endif /* JSMN_H */ 472 | -------------------------------------------------------------------------------- /src/reuse/log.h: -------------------------------------------------------------------------------- 1 | // Developed by Simen Haugo. 2 | // See LICENSE.txt for copyright and licensing details (standard MIT License). 3 | 4 | #pragma once 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static struct logfile_t 11 | { 12 | size_t bytes; 13 | size_t capacity; 14 | char *begin; 15 | char *str; 16 | } logfile; 17 | 18 | static void log_init() 19 | { 20 | logfile.capacity = 1024*1024; 21 | logfile.begin = (char*)malloc(logfile.capacity*sizeof(char)); 22 | logfile.str = logfile.begin; 23 | logfile.str[0] = '\0'; 24 | assert(logfile.begin); 25 | } 26 | 27 | static void log_clear() 28 | { 29 | if (!logfile.begin) 30 | log_init(); 31 | assert(logfile.begin); 32 | logfile.str = logfile.begin; 33 | logfile.str[0] = '\0'; 34 | logfile.bytes = 0; 35 | } 36 | 37 | static void log_err(const char *fmt, ...) 38 | { 39 | va_list args; 40 | va_start(args, fmt); 41 | int bytes = vfprintf(stderr, fmt, args); 42 | va_end(args); 43 | 44 | if (!logfile.begin) 45 | log_init(); 46 | 47 | assert(logfile.begin); 48 | assert(logfile.str); 49 | assert(logfile.capacity > 0); 50 | assert(logfile.bytes <= logfile.capacity); 51 | 52 | if (logfile.bytes + bytes < logfile.capacity) 53 | { 54 | va_start(args, fmt); 55 | logfile.str += vsprintf(logfile.str, fmt, args); 56 | va_end(args); 57 | logfile.bytes += bytes; 58 | } 59 | } 60 | 61 | static const char *log_get_buffer() 62 | { 63 | if (!logfile.begin) 64 | log_init(); 65 | return logfile.begin; 66 | } 67 | -------------------------------------------------------------------------------- /src/widgets/Camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void compute_view_matrix(float dst[4*4], float3 t, float3 r) 4 | { 5 | float cx = cosf(r.x); 6 | float cy = cosf(r.y); 7 | float cz = cosf(r.z); 8 | float sx = sinf(r.x); 9 | float sy = sinf(r.y); 10 | float sz = sinf(r.z); 11 | 12 | float dtx = t.z*(sx*sz + cx*cz*sy) - t.y*(cx*sz - cz*sx*sy) + t.x*cy*cz; 13 | float dty = t.y*(cx*cz + sx*sy*sz) - t.z*(cz*sx - cx*sy*sz) + t.x*cy*sz; 14 | float dtz = t.z*cx*cy - t.x*sy + t.y*cy*sx; 15 | 16 | // q = R*(p + t) 17 | dst[ 0] = cy*cz; dst[ 1] = cz*sx*sy - cx*sz; dst[ 2] = sx*sz + cx*cz*sy; dst[ 3] = dtx; 18 | dst[ 4] = cy*sz; dst[ 5] = cx*cz + sx*sy*sz; dst[ 6] = cx*sy*sz - cz*sx; dst[ 7] = dty; 19 | dst[ 8] = -sy; dst[ 9] = cy*sx; dst[10] = cx*cy; dst[11] = dtz; 20 | dst[12] = 0.0f; dst[13] = 0.0f; dst[14] = 0.0f; dst[15] = 0.0f; 21 | } 22 | 23 | void invert_view_matrix(float dst[4*4], float src[4*4]) 24 | { 25 | dst[ 0] = src[ 0]; dst[ 1] = src[4]; dst[ 2] = src[8]; dst[ 3] = -(src[0]*src[3] + src[4]*src[7] + src[8]*src[11]); 26 | dst[ 4] = src[ 1]; dst[ 5] = src[5]; dst[ 6] = src[9]; dst[ 7] = -(src[1]*src[3] + src[5]*src[7] + src[9]*src[11]); 27 | dst[ 8] = src[ 2]; dst[ 9] = src[6]; dst[10] = src[10]; dst[11] = -(src[2]*src[3] + src[6]*src[7] + src[10]*src[11]); 28 | dst[12] = 0.0f; dst[13] = 0.0f; dst[14] = 0.0f; dst[15] = 0.0f; 29 | } 30 | 31 | float3 transform_point(float m[4*4], float3 v) 32 | { 33 | float3 r = 34 | { 35 | m[0]*v.x + m[1]*v.y + m[2]*v.z + m[3], 36 | m[4]*v.x + m[5]*v.y + m[6]*v.z + m[7], 37 | m[8]*v.x + m[9]*v.y + m[10]*v.z + m[11] 38 | }; 39 | return r; 40 | } 41 | 42 | struct Widget_Camera : Widget 43 | { 44 | angle2 dir; 45 | float3 pos; 46 | float camera_yfov; 47 | float2 camera_shift; 48 | int loc_iView; 49 | int loc_iCameraF; 50 | int loc_iCameraCenter; 51 | 52 | virtual void default_values() 53 | { 54 | dir.theta = -20.0f; 55 | dir.phi = 30.0f; 56 | pos.x = 0.0f; 57 | pos.y = 0.0f; 58 | pos.z = 24.0f; 59 | camera_yfov = 10.0f; 60 | camera_shift.x = 0.0f; 61 | camera_shift.y = 0.0f; 62 | } 63 | virtual void deserialize(const char **cc) 64 | { 65 | while (parse_next_in_list(cc)) { 66 | if (parse_argument_float(cc, "yfov", &camera_yfov)) ; 67 | else if (parse_argument_float2(cc, "shift", &camera_shift)) ; 68 | else if (parse_argument_angle2(cc, "dir", &dir)) ; 69 | else if (parse_argument_float3(cc, "pos", &pos)) ; 70 | else parse_list_unexpected(); 71 | } 72 | } 73 | virtual void serialize(FILE *f) 74 | { 75 | fprintf(f, "camera=("); 76 | fprintf(f, "yfov=%g, ", camera_yfov); 77 | fprintf(f, "shift=(%g, %g), ", camera_shift.x, camera_shift.y); 78 | fprintf(f, "dir=(%g deg, %g deg), ", dir.theta, dir.phi); 79 | fprintf(f, "pos=(%g, %g, %g))", pos.x, pos.y, pos.z); 80 | } 81 | virtual void get_param_offsets(fKernel *f) 82 | { 83 | loc_iView = fraktal_get_param_offset(f, "iView"); 84 | loc_iCameraCenter = fraktal_get_param_offset(f, "iCameraCenter"); 85 | loc_iCameraF = fraktal_get_param_offset(f, "iCameraF"); 86 | } 87 | virtual bool is_active() 88 | { 89 | if (loc_iView < 0) return false; 90 | if (loc_iCameraCenter < 0) return false; 91 | if (loc_iCameraF < 0) return false; 92 | return true; 93 | } 94 | virtual bool update(guiState &g) 95 | { 96 | bool changed = false; 97 | 98 | // rotation 99 | int rotate_step = 5; 100 | if (g.keys.Left.pressed) { dir.phi -= rotate_step; changed = true; } 101 | if (g.keys.Right.pressed) { dir.phi += rotate_step; changed = true; } 102 | if (g.keys.Up.pressed) { dir.theta -= rotate_step; changed = true; } 103 | if (g.keys.Down.pressed) { dir.theta += rotate_step; changed = true; } 104 | 105 | // translation 106 | // Note: The z_over_f factor ensures that a key press yields the same 107 | // displacement of the object in image pixels, irregardless of how far 108 | // away the camera is. 109 | float f = yfov2pinhole_f(camera_yfov, (float)g.resolution.y); 110 | float z_over_f = fabsf(pos.z)/f; 111 | float x_move_step = (g.resolution.x*0.05f)*z_over_f; 112 | float y_move_step = (g.resolution.y*0.05f)*z_over_f; 113 | float z_move_step = 0.1f*fabsf(pos.z); 114 | if (g.keys.Ctrl.pressed) { pos.y -= y_move_step; changed = true; } 115 | if (g.keys.Space.pressed) { pos.y += y_move_step; changed = true; } 116 | if (g.keys.A.pressed) { pos.x -= x_move_step; changed = true; } 117 | if (g.keys.D.pressed) { pos.x += x_move_step; changed = true; } 118 | if (g.keys.W.pressed) { pos.z -= z_move_step; changed = true; } 119 | if (g.keys.S.pressed) { pos.z += z_move_step; changed = true; } 120 | 121 | if (ImGui::CollapsingHeader("Camera", ImGuiTreeNodeFlags_DefaultOpen)) 122 | { 123 | float3 drag_speeds; 124 | drag_speeds.x = (g.resolution.x*0.005f)*z_over_f; 125 | drag_speeds.y = (g.resolution.y*0.005f)*z_over_f; 126 | drag_speeds.z = 0.01f*fabsf(pos.z); 127 | 128 | if (loc_iView != -1) 129 | { 130 | changed |= ImGui::DragFloat("\xce\xb8##view_dir", &dir.theta, 1.0f, -90.0f, +90.0f, "%.0f deg"); 131 | changed |= ImGui::DragFloat("\xcf\x86##view_dir", &dir.phi, 1.0f, -180.0f, +180.0f, "%.0f deg"); 132 | changed |= ImGui::DragFloat3("Position##view_pos", &pos.x, &drag_speeds.x); 133 | } 134 | if (loc_iCameraF != -1) 135 | changed |= ImGui::DragFloat("Field of view##camera_yfov", &camera_yfov, 0.1f, 1.0f, 90.0f, "%.1f deg"); 136 | if (loc_iCameraCenter != -1) 137 | changed |= ImGui::DragFloat2("Shift##camera_shift", &camera_shift.x, 0.01f, -1.0f, +1.0f); 138 | } 139 | 140 | return changed; 141 | } 142 | virtual void set_params(guiState &g) 143 | { 144 | float cx = (0.5f + 0.5f*camera_shift.x)*g.resolution.x; 145 | float cy = (0.5f + 0.5f*camera_shift.y)*g.resolution.y; 146 | float f = yfov2pinhole_f(camera_yfov, (float)g.resolution.y); 147 | fraktal_param_2f(loc_iCameraCenter, cx, cy); 148 | fraktal_param_1f(loc_iCameraF, f); 149 | float iView[4*4]; 150 | float3 r = { 151 | deg2rad(dir.theta), 152 | deg2rad(dir.phi), 153 | 0.0f 154 | }; 155 | compute_view_matrix(iView, pos, r); 156 | fraktal_param_transpose_matrix4f(loc_iView, iView); 157 | } 158 | }; 159 | -------------------------------------------------------------------------------- /src/widgets/Geometry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "colormap_inferno.h" 3 | 4 | static fArray *f_colormap_inferno; 5 | 6 | struct Widget_Geometry : Widget 7 | { 8 | float min_distance; 9 | float max_distance; 10 | float min_thickness; 11 | float max_thickness; 12 | bool apply_colormap; 13 | int loc_iMinDistance; 14 | int loc_iMaxDistance; 15 | int loc_iMinThickness; 16 | int loc_iMaxThickness; 17 | int loc_iApplyColormap; 18 | int loc_iColormap; 19 | 20 | virtual void default_values() 21 | { 22 | min_distance = 10.0f; 23 | max_distance = 30.0f; 24 | min_thickness = 0.0f; 25 | max_thickness = 0.5f; 26 | apply_colormap = false; 27 | 28 | if (!f_colormap_inferno) 29 | { 30 | f_colormap_inferno = fraktal_create_array( 31 | colormap_inferno, 32 | colormap_inferno_length, 33 | 1, 34 | 4, 35 | FRAKTAL_FLOAT, 36 | FRAKTAL_READ_ONLY 37 | ); 38 | assert(f_colormap_inferno); 39 | } 40 | 41 | } 42 | virtual void deserialize(const char **cc) 43 | { 44 | while (parse_next_in_list(cc)) { 45 | if (parse_argument_float(cc, "min_distance", &min_distance)) ; 46 | else if (parse_argument_float(cc, "max_distance", &max_distance)) ; 47 | else if (parse_argument_float(cc, "min_thickness", &min_thickness)) ; 48 | else if (parse_argument_float(cc, "max_thickness", &max_thickness)) ; 49 | else if (parse_argument_bool(cc, "apply_colormap", &apply_colormap)) ; 50 | else parse_list_unexpected(); 51 | } 52 | } 53 | virtual void serialize(FILE *f) 54 | { 55 | 56 | } 57 | virtual void get_param_offsets(fKernel *f) 58 | { 59 | loc_iMinDistance = fraktal_get_param_offset(f, "iMinDistance"); 60 | loc_iMaxDistance = fraktal_get_param_offset(f, "iMaxDistance"); 61 | loc_iMinThickness = fraktal_get_param_offset(f, "iMinThickness"); 62 | loc_iMaxThickness = fraktal_get_param_offset(f, "iMaxThickness"); 63 | loc_iApplyColormap = fraktal_get_param_offset(f, "iApplyColormap"); 64 | loc_iColormap = fraktal_get_param_offset(f, "iColormap"); 65 | } 66 | virtual bool is_active() 67 | { 68 | if (loc_iMinDistance < 0) return false; 69 | if (loc_iMaxDistance < 0) return false; 70 | if (loc_iMinThickness < 0) return false; 71 | if (loc_iMaxThickness < 0) return false; 72 | if (loc_iApplyColormap < 0) return false; 73 | if (loc_iColormap < 0) return false; 74 | return true; 75 | } 76 | virtual bool update(guiState &g) 77 | { 78 | bool changed = false; 79 | if (ImGui::CollapsingHeader("Geometry")) 80 | { 81 | changed |= ImGui::Checkbox("Apply colormap", &apply_colormap); 82 | changed |= ImGui::DragFloat("Min. depth", &min_distance, 0.1f); 83 | changed |= ImGui::DragFloat("Max. depth", &max_distance, 0.1f); 84 | changed |= ImGui::DragFloat("Min. thickness", &min_thickness, 0.1f); 85 | changed |= ImGui::DragFloat("Max. thickness", &max_thickness, 0.1f); 86 | } 87 | return changed; 88 | } 89 | virtual void set_params(guiState &g) 90 | { 91 | fraktal_param_1f(loc_iMinDistance, min_distance); 92 | fraktal_param_1f(loc_iMaxDistance, max_distance); 93 | fraktal_param_1f(loc_iMinThickness, min_thickness); 94 | fraktal_param_1f(loc_iMaxThickness, max_thickness); 95 | fraktal_param_1i(loc_iApplyColormap, apply_colormap ? 1 : 0); 96 | fraktal_param_array(loc_iColormap, f_colormap_inferno); 97 | } 98 | }; 99 | -------------------------------------------------------------------------------- /src/widgets/Ground.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Widget_Ground : Widget 4 | { 5 | bool isolines_enabled; 6 | float3 isolines_color; 7 | float isolines_thickness; 8 | float isolines_spacing; 9 | int isolines_count; 10 | bool ground_reflective; 11 | float ground_height; 12 | float ground_specular_exponent; 13 | float ground_reflectivity; 14 | 15 | int loc_iDrawIsolines; 16 | int loc_iIsolineColor; 17 | int loc_iIsolineThickness; 18 | int loc_iIsolineSpacing; 19 | int loc_iIsolineMax; 20 | int loc_iGroundReflective; 21 | int loc_iGroundHeight; 22 | int loc_iGroundSpecularExponent; 23 | int loc_iGroundReflectivity; 24 | 25 | virtual void default_values() 26 | { 27 | isolines_enabled = false; 28 | isolines_color.x = 0.3f; 29 | isolines_color.y = 0.3f; 30 | isolines_color.z = 0.3f; 31 | isolines_thickness = 0.25f*0.5f; 32 | isolines_spacing = 0.4f; 33 | isolines_count = 3; 34 | ground_reflective = false; 35 | ground_height = 0.0f; 36 | ground_specular_exponent = 500.0f; 37 | ground_reflectivity = 0.6f; 38 | 39 | } 40 | virtual void deserialize(const char **cc) 41 | { 42 | while (parse_next_in_list(cc)) { 43 | if (parse_argument_float3(cc, "isolines_color", &isolines_color)) ; 44 | else if (parse_argument_bool(cc, "draw_isolines", &isolines_enabled)) ; 45 | else if (parse_argument_float(cc, "isolines_thickness", &isolines_thickness)) ; 46 | else if (parse_argument_float(cc, "isolines_spacing", &isolines_spacing)) ; 47 | else if (parse_argument_int(cc, "isolines_count", &isolines_count)) ; 48 | else if (parse_argument_float(cc, "height", &ground_height)) ; 49 | else if (parse_argument_float(cc, "specular_exponent", &ground_specular_exponent)) ; 50 | else if (parse_argument_float(cc, "reflectivity", &ground_reflectivity)) ; 51 | else parse_list_unexpected(); 52 | } 53 | } 54 | virtual void serialize(FILE *f) 55 | { 56 | 57 | } 58 | virtual void get_param_offsets(fKernel *f) 59 | { 60 | loc_iDrawIsolines = fraktal_get_param_offset(f, "iDrawIsolines"); 61 | loc_iIsolineColor = fraktal_get_param_offset(f, "iIsolineColor"); 62 | loc_iIsolineThickness = fraktal_get_param_offset(f, "iIsolineThickness"); 63 | loc_iIsolineSpacing = fraktal_get_param_offset(f, "iIsolineSpacing"); 64 | loc_iIsolineMax = fraktal_get_param_offset(f, "iIsolineMax"); 65 | loc_iGroundReflective = fraktal_get_param_offset(f, "iGroundReflective"); 66 | loc_iGroundHeight = fraktal_get_param_offset(f, "iGroundHeight"); 67 | loc_iGroundSpecularExponent = fraktal_get_param_offset(f, "iGroundSpecularExponent"); 68 | loc_iGroundReflectivity = fraktal_get_param_offset(f, "iGroundReflectivity"); 69 | } 70 | virtual bool is_active() 71 | { 72 | if (loc_iGroundHeight < 0) return false; 73 | return true; 74 | } 75 | virtual bool update(guiState &g) 76 | { 77 | bool changed = false; 78 | if (ImGui::CollapsingHeader("Ground")) 79 | { 80 | changed |= ImGui::DragFloat("Height", &ground_height, 0.01f); 81 | 82 | if (loc_iDrawIsolines >= 0 && ImGui::TreeNode("Isolines")) 83 | { 84 | changed |= ImGui::Checkbox("Enabled##Isolines", &isolines_enabled); 85 | changed |= ImGui::ColorEdit3("Color", &isolines_color.x); 86 | changed |= ImGui::DragFloat("Thickness", &isolines_thickness, 0.01f); 87 | changed |= ImGui::DragFloat("Spacing", &isolines_spacing, 0.01f); 88 | changed |= ImGui::DragInt("Count", &isolines_count, 0.1f, 0, 100); 89 | ImGui::TreePop(); 90 | } 91 | 92 | if (loc_iGroundReflective >= 0 && ImGui::TreeNode("Reflection")) 93 | { 94 | changed |= ImGui::Checkbox("Enabled##Reflection", &ground_reflective); 95 | changed |= ImGui::DragFloat("Exponent", &ground_specular_exponent, 1.0f, 0.0f, 10000.0f); 96 | changed |= ImGui::SliderFloat("Reflectivity", &ground_reflectivity, 0.0f, 1.0f); 97 | ImGui::TreePop(); 98 | } 99 | } 100 | return changed; 101 | } 102 | virtual void set_params(guiState &g) 103 | { 104 | fraktal_param_1i(loc_iDrawIsolines, isolines_enabled ? 1 : 0); 105 | fraktal_param_3f(loc_iIsolineColor, isolines_color.x, isolines_color.y, isolines_color.z); 106 | fraktal_param_1f(loc_iIsolineThickness, isolines_thickness); 107 | fraktal_param_1f(loc_iIsolineSpacing, isolines_spacing); 108 | fraktal_param_1f(loc_iIsolineMax, isolines_count*isolines_spacing + isolines_thickness*0.5f); 109 | fraktal_param_1i(loc_iGroundReflective, ground_reflective ? 1 : 0); 110 | fraktal_param_1f(loc_iGroundHeight, ground_height); 111 | fraktal_param_1f(loc_iGroundSpecularExponent, ground_specular_exponent); 112 | fraktal_param_1f(loc_iGroundReflectivity, ground_reflectivity); 113 | } 114 | }; 115 | -------------------------------------------------------------------------------- /src/widgets/Material.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Widget_Material : Widget 4 | { 5 | bool glossy; 6 | float3 specular_albedo; 7 | float specular_exponent; 8 | float3 albedo; 9 | int loc_iMaterialGlossy; 10 | int loc_iMaterialSpecularExponent; 11 | int loc_iMaterialSpecularAlbedo; 12 | int loc_iMaterialAlbedo; 13 | 14 | virtual void default_values() 15 | { 16 | glossy = true; 17 | specular_albedo.x = 0.3f; 18 | specular_albedo.y = 0.3f; 19 | specular_albedo.z = 0.3f; 20 | specular_exponent = 32.0f; 21 | albedo.x = 0.6f; 22 | albedo.y = 0.1f; 23 | albedo.z = 0.1f; 24 | 25 | } 26 | virtual void deserialize(const char **cc) 27 | { 28 | while (parse_next_in_list(cc)) { 29 | if (parse_argument_float3(cc, "albedo", &albedo)) ; 30 | else if (parse_argument_float3(cc, "specular_albedo", &specular_albedo)) ; 31 | else if (parse_argument_float(cc, "specular_exponent", &specular_exponent)) ; 32 | else if (parse_argument_bool(cc, "glossy", &glossy)) ; 33 | else parse_list_unexpected(); 34 | } 35 | } 36 | virtual void serialize(FILE *f) 37 | { 38 | 39 | } 40 | virtual void get_param_offsets(fKernel *f) 41 | { 42 | loc_iMaterialGlossy = fraktal_get_param_offset(f, "iMaterialGlossy"); 43 | loc_iMaterialSpecularExponent = fraktal_get_param_offset(f, "iMaterialSpecularExponent"); 44 | loc_iMaterialSpecularAlbedo = fraktal_get_param_offset(f, "iMaterialSpecularAlbedo"); 45 | loc_iMaterialAlbedo = fraktal_get_param_offset(f, "iMaterialAlbedo"); 46 | } 47 | virtual bool is_active() 48 | { 49 | if (loc_iMaterialGlossy < 0) return false; 50 | if (loc_iMaterialSpecularExponent < 0) return false; 51 | if (loc_iMaterialSpecularAlbedo < 0) return false; 52 | if (loc_iMaterialAlbedo < 0) return false; 53 | return true; 54 | } 55 | virtual bool update(guiState &g) 56 | { 57 | bool changed = false; 58 | if (ImGui::CollapsingHeader("Material")) 59 | { 60 | changed |= ImGui::Checkbox("Glossy", &glossy); 61 | changed |= ImGui::ColorEdit3("Albedo", &albedo.x); 62 | changed |= ImGui::ColorEdit3("Specular", &specular_albedo.x); 63 | changed |= ImGui::DragFloat("Exponent", &specular_exponent, 1.0f, 0.0f, 1000.0f); 64 | } 65 | return changed; 66 | } 67 | virtual void set_params(guiState &g) 68 | { 69 | fraktal_param_1i(loc_iMaterialGlossy, glossy ? 1 : 0); 70 | fraktal_param_1f(loc_iMaterialSpecularExponent, specular_exponent); 71 | fraktal_param_3f(loc_iMaterialSpecularAlbedo, specular_albedo.x, specular_albedo.y, specular_albedo.z); 72 | fraktal_param_3f(loc_iMaterialAlbedo, albedo.x, albedo.y, albedo.z); 73 | } 74 | }; 75 | -------------------------------------------------------------------------------- /src/widgets/Sun.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Widget_Sun : Widget 4 | { 5 | float size; 6 | angle2 dir; 7 | float3 color; 8 | float intensity; 9 | int loc_iSunStrength; 10 | int loc_iCosSunSize; 11 | int loc_iToSun; 12 | 13 | virtual void default_values() 14 | { 15 | size = 3.0f; 16 | dir.theta = 30.0f; 17 | dir.phi = 90.0f; 18 | color.x = 1.0f; 19 | color.y = 1.0f; 20 | color.z = 0.8f; 21 | intensity = 250.0f; 22 | } 23 | virtual void deserialize(const char **cc) 24 | { 25 | while (parse_next_in_list(cc)) { 26 | if (parse_argument_angle(cc, "size", &size)) ; 27 | else if (parse_argument_angle2(cc, "dir", &dir)) ; 28 | else if (parse_argument_float3(cc, "color", &color)) ; 29 | else if (parse_argument_float(cc, "intensity", &intensity)) ; 30 | else parse_list_unexpected(); 31 | } 32 | } 33 | virtual void serialize(FILE *f) 34 | { 35 | 36 | } 37 | virtual void get_param_offsets(fKernel *f) 38 | { 39 | loc_iSunStrength = fraktal_get_param_offset(f, "iSunStrength"); 40 | loc_iCosSunSize = fraktal_get_param_offset(f, "iCosSunSize"); 41 | loc_iToSun = fraktal_get_param_offset(f, "iToSun"); 42 | } 43 | virtual bool is_active() 44 | { 45 | if (loc_iCosSunSize < 0) return false; 46 | if (loc_iToSun < 0) return false; 47 | return true; 48 | } 49 | virtual bool update(guiState &g) 50 | { 51 | bool changed = false; 52 | if (ImGui::CollapsingHeader("Sun")) 53 | { 54 | changed |= ImGui::SliderFloat("Size##sun_size", &size, 0.0f, 180.0f, "%.0f deg", 2.0f); 55 | changed |= ImGui::SliderFloat("\xce\xb8##sun_dir", &dir.theta, -90.0f, +90.0f, "%.0f deg"); 56 | changed |= ImGui::SliderFloat("\xcf\x86##sun_dir", &dir.phi, -180.0f, +180.0f, "%.0f deg"); 57 | changed |= ImGui::SliderFloat3("Color##sun_color", &color.x, 0.0f, 1.0f); 58 | changed |= ImGui::DragFloat("Intensity##sun_intensity", &intensity); 59 | } 60 | return changed; 61 | } 62 | virtual void set_params(guiState &g) 63 | { 64 | float3 iSunStrength = color; 65 | iSunStrength.x *= intensity; 66 | iSunStrength.y *= intensity; 67 | iSunStrength.z *= intensity; 68 | float3 iToSun = angle2float3(dir); 69 | float iCosSunSize = cosf(deg2rad(size)/2.0f); 70 | fraktal_param_3f(loc_iSunStrength, iSunStrength.x, iSunStrength.y, iSunStrength.z); 71 | fraktal_param_3f(loc_iToSun, iToSun.x, iToSun.y, iToSun.z); 72 | fraktal_param_1f(loc_iCosSunSize, iCosSunSize); 73 | } 74 | }; 75 | -------------------------------------------------------------------------------- /src/widgets/Widget.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct Widget 4 | { 5 | virtual void default_values() = 0; 6 | virtual void deserialize(const char **cc) = 0; 7 | virtual void serialize(FILE *f) = 0; 8 | virtual void get_param_offsets(fKernel *f) = 0; 9 | virtual bool is_active() = 0; 10 | virtual bool update(guiState &g) = 0; 11 | virtual void set_params(guiState &g) = 0; 12 | }; 13 | -------------------------------------------------------------------------------- /src/widgets/colormap_inferno.h: -------------------------------------------------------------------------------- 1 | const float colormap_inferno[] = { 2 | 1.46159096e-03f, 4.66127766e-04f, 1.38655200e-02f, 1.0f, 3 | 2.25764007e-03f, 1.29495431e-03f, 1.83311461e-02f, 1.0f, 4 | 3.27943222e-03f, 2.30452991e-03f, 2.37083291e-02f, 1.0f, 5 | 4.51230222e-03f, 3.49037666e-03f, 2.99647059e-02f, 1.0f, 6 | 5.94976987e-03f, 4.84285000e-03f, 3.71296695e-02f, 1.0f, 7 | 7.58798550e-03f, 6.35613622e-03f, 4.49730774e-02f, 1.0f, 8 | 9.42604390e-03f, 8.02185006e-03f, 5.28443561e-02f, 1.0f, 9 | 1.14654337e-02f, 9.82831486e-03f, 6.07496380e-02f, 1.0f, 10 | 1.37075706e-02f, 1.17705913e-02f, 6.86665843e-02f, 1.0f, 11 | 1.61557566e-02f, 1.38404966e-02f, 7.66026660e-02f, 1.0f, 12 | 1.88153670e-02f, 1.60262753e-02f, 8.45844897e-02f, 1.0f, 13 | 2.16919340e-02f, 1.83201254e-02f, 9.26101050e-02f, 1.0f, 14 | 2.47917814e-02f, 2.07147875e-02f, 1.00675555e-01f, 1.0f, 15 | 2.81228154e-02f, 2.32009284e-02f, 1.08786954e-01f, 1.0f, 16 | 3.16955304e-02f, 2.57651161e-02f, 1.16964722e-01f, 1.0f, 17 | 3.55204468e-02f, 2.83974570e-02f, 1.25209396e-01f, 1.0f, 18 | 3.96084872e-02f, 3.10895652e-02f, 1.33515085e-01f, 1.0f, 19 | 4.38295350e-02f, 3.38299885e-02f, 1.41886249e-01f, 1.0f, 20 | 4.80616391e-02f, 3.66066101e-02f, 1.50326989e-01f, 1.0f, 21 | 5.23204388e-02f, 3.94066020e-02f, 1.58841025e-01f, 1.0f, 22 | 5.66148978e-02f, 4.21598925e-02f, 1.67445592e-01f, 1.0f, 23 | 6.09493930e-02f, 4.47944924e-02f, 1.76128834e-01f, 1.0f, 24 | 6.53301801e-02f, 4.73177796e-02f, 1.84891506e-01f, 1.0f, 25 | 6.97637296e-02f, 4.97264666e-02f, 1.93735088e-01f, 1.0f, 26 | 7.42565152e-02f, 5.20167766e-02f, 2.02660374e-01f, 1.0f, 27 | 7.88150034e-02f, 5.41844801e-02f, 2.11667355e-01f, 1.0f, 28 | 8.34456313e-02f, 5.62249365e-02f, 2.20755099e-01f, 1.0f, 29 | 8.81547730e-02f, 5.81331465e-02f, 2.29921611e-01f, 1.0f, 30 | 9.29486914e-02f, 5.99038167e-02f, 2.39163669e-01f, 1.0f, 31 | 9.78334770e-02f, 6.15314414e-02f, 2.48476662e-01f, 1.0f, 32 | 1.02814972e-01f, 6.30104053e-02f, 2.57854400e-01f, 1.0f, 33 | 1.07898679e-01f, 6.43351102e-02f, 2.67288933e-01f, 1.0f, 34 | 1.13094451e-01f, 6.54920358e-02f, 2.76783978e-01f, 1.0f, 35 | 1.18405035e-01f, 6.64791593e-02f, 2.86320656e-01f, 1.0f, 36 | 1.23832651e-01f, 6.72946449e-02f, 2.95879431e-01f, 1.0f, 37 | 1.29380192e-01f, 6.79349264e-02f, 3.05442931e-01f, 1.0f, 38 | 1.35053322e-01f, 6.83912798e-02f, 3.14999890e-01f, 1.0f, 39 | 1.40857952e-01f, 6.86540710e-02f, 3.24537640e-01f, 1.0f, 40 | 1.46785234e-01f, 6.87382323e-02f, 3.34011109e-01f, 1.0f, 41 | 1.52839217e-01f, 6.86368599e-02f, 3.43404450e-01f, 1.0f, 42 | 1.59017511e-01f, 6.83540225e-02f, 3.52688028e-01f, 1.0f, 43 | 1.65308131e-01f, 6.79108689e-02f, 3.61816426e-01f, 1.0f, 44 | 1.71713033e-01f, 6.73053260e-02f, 3.70770827e-01f, 1.0f, 45 | 1.78211730e-01f, 6.65758073e-02f, 3.79497161e-01f, 1.0f, 46 | 1.84800877e-01f, 6.57324381e-02f, 3.87972507e-01f, 1.0f, 47 | 1.91459745e-01f, 6.48183312e-02f, 3.96151969e-01f, 1.0f, 48 | 1.98176877e-01f, 6.38624166e-02f, 4.04008953e-01f, 1.0f, 49 | 2.04934882e-01f, 6.29066192e-02f, 4.11514273e-01f, 1.0f, 50 | 2.11718061e-01f, 6.19917876e-02f, 4.18646741e-01f, 1.0f, 51 | 2.18511590e-01f, 6.11584918e-02f, 4.25391816e-01f, 1.0f, 52 | 2.25302032e-01f, 6.04451843e-02f, 4.31741767e-01f, 1.0f, 53 | 2.32076515e-01f, 5.98886855e-02f, 4.37694665e-01f, 1.0f, 54 | 2.38825991e-01f, 5.95170384e-02f, 4.43255999e-01f, 1.0f, 55 | 2.45543175e-01f, 5.93524384e-02f, 4.48435938e-01f, 1.0f, 56 | 2.52220252e-01f, 5.94147119e-02f, 4.53247729e-01f, 1.0f, 57 | 2.58857304e-01f, 5.97055998e-02f, 4.57709924e-01f, 1.0f, 58 | 2.65446744e-01f, 6.02368754e-02f, 4.61840297e-01f, 1.0f, 59 | 2.71994089e-01f, 6.09935552e-02f, 4.65660375e-01f, 1.0f, 60 | 2.78493300e-01f, 6.19778136e-02f, 4.69190328e-01f, 1.0f, 61 | 2.84951097e-01f, 6.31676261e-02f, 4.72450879e-01f, 1.0f, 62 | 2.91365817e-01f, 6.45534486e-02f, 4.75462193e-01f, 1.0f, 63 | 2.97740413e-01f, 6.61170432e-02f, 4.78243482e-01f, 1.0f, 64 | 3.04080941e-01f, 6.78353452e-02f, 4.80811572e-01f, 1.0f, 65 | 3.10382027e-01f, 6.97024767e-02f, 4.83186340e-01f, 1.0f, 66 | 3.16654235e-01f, 7.16895272e-02f, 4.85380429e-01f, 1.0f, 67 | 3.22899126e-01f, 7.37819504e-02f, 4.87408399e-01f, 1.0f, 68 | 3.29114038e-01f, 7.59715081e-02f, 4.89286796e-01f, 1.0f, 69 | 3.35307503e-01f, 7.82361045e-02f, 4.91024144e-01f, 1.0f, 70 | 3.41481725e-01f, 8.05635079e-02f, 4.92631321e-01f, 1.0f, 71 | 3.47635742e-01f, 8.29463512e-02f, 4.94120923e-01f, 1.0f, 72 | 3.53773161e-01f, 8.53726329e-02f, 4.95501096e-01f, 1.0f, 73 | 3.59897941e-01f, 8.78311772e-02f, 4.96778331e-01f, 1.0f, 74 | 3.66011928e-01f, 9.03143031e-02f, 4.97959963e-01f, 1.0f, 75 | 3.72116205e-01f, 9.28159917e-02f, 4.99053326e-01f, 1.0f, 76 | 3.78210547e-01f, 9.53322947e-02f, 5.00066568e-01f, 1.0f, 77 | 3.84299445e-01f, 9.78549106e-02f, 5.01001964e-01f, 1.0f, 78 | 3.90384361e-01f, 1.00379466e-01f, 5.01864236e-01f, 1.0f, 79 | 3.96466670e-01f, 1.02902194e-01f, 5.02657590e-01f, 1.0f, 80 | 4.02547663e-01f, 1.05419865e-01f, 5.03385761e-01f, 1.0f, 81 | 4.08628505e-01f, 1.07929771e-01f, 5.04052118e-01f, 1.0f, 82 | 4.14708664e-01f, 1.10431177e-01f, 5.04661843e-01f, 1.0f, 83 | 4.20791157e-01f, 1.12920210e-01f, 5.05214935e-01f, 1.0f, 84 | 4.26876965e-01f, 1.15395258e-01f, 5.05713602e-01f, 1.0f, 85 | 4.32967001e-01f, 1.17854987e-01f, 5.06159754e-01f, 1.0f, 86 | 4.39062114e-01f, 1.20298314e-01f, 5.06555026e-01f, 1.0f, 87 | 4.45163096e-01f, 1.22724371e-01f, 5.06900806e-01f, 1.0f, 88 | 4.51270678e-01f, 1.25132484e-01f, 5.07198258e-01f, 1.0f, 89 | 4.57385535e-01f, 1.27522145e-01f, 5.07448336e-01f, 1.0f, 90 | 4.63508291e-01f, 1.29892998e-01f, 5.07651812e-01f, 1.0f, 91 | 4.69639514e-01f, 1.32244819e-01f, 5.07809282e-01f, 1.0f, 92 | 4.75779723e-01f, 1.34577500e-01f, 5.07921193e-01f, 1.0f, 93 | 4.81928997e-01f, 1.36891390e-01f, 5.07988509e-01f, 1.0f, 94 | 4.88088169e-01f, 1.39186217e-01f, 5.08010737e-01f, 1.0f, 95 | 4.94257673e-01f, 1.41462106e-01f, 5.07987836e-01f, 1.0f, 96 | 5.00437834e-01f, 1.43719323e-01f, 5.07919772e-01f, 1.0f, 97 | 5.06628929e-01f, 1.45958202e-01f, 5.07806420e-01f, 1.0f, 98 | 5.12831195e-01f, 1.48179144e-01f, 5.07647570e-01f, 1.0f, 99 | 5.19044825e-01f, 1.50382611e-01f, 5.07442938e-01f, 1.0f, 100 | 5.25269968e-01f, 1.52569121e-01f, 5.07192172e-01f, 1.0f, 101 | 5.31506735e-01f, 1.54739247e-01f, 5.06894860e-01f, 1.0f, 102 | 5.37755194e-01f, 1.56893613e-01f, 5.06550538e-01f, 1.0f, 103 | 5.44015371e-01f, 1.59032895e-01f, 5.06158696e-01f, 1.0f, 104 | 5.50287252e-01f, 1.61157816e-01f, 5.05718782e-01f, 1.0f, 105 | 5.56570783e-01f, 1.63269149e-01f, 5.05230210e-01f, 1.0f, 106 | 5.62865867e-01f, 1.65367714e-01f, 5.04692365e-01f, 1.0f, 107 | 5.69172368e-01f, 1.67454379e-01f, 5.04104606e-01f, 1.0f, 108 | 5.75490107e-01f, 1.69530062e-01f, 5.03466273e-01f, 1.0f, 109 | 5.81818864e-01f, 1.71595728e-01f, 5.02776690e-01f, 1.0f, 110 | 5.88158375e-01f, 1.73652392e-01f, 5.02035167e-01f, 1.0f, 111 | 5.94508337e-01f, 1.75701122e-01f, 5.01241011e-01f, 1.0f, 112 | 6.00868399e-01f, 1.77743036e-01f, 5.00393522e-01f, 1.0f, 113 | 6.07238169e-01f, 1.79779309e-01f, 4.99491999e-01f, 1.0f, 114 | 6.13617209e-01f, 1.81811170e-01f, 4.98535746e-01f, 1.0f, 115 | 6.20005032e-01f, 1.83839907e-01f, 4.97524075e-01f, 1.0f, 116 | 6.26401108e-01f, 1.85866869e-01f, 4.96456304e-01f, 1.0f, 117 | 6.32804854e-01f, 1.87893468e-01f, 4.95331769e-01f, 1.0f, 118 | 6.39215638e-01f, 1.89921182e-01f, 4.94149821e-01f, 1.0f, 119 | 6.45632778e-01f, 1.91951556e-01f, 4.92909832e-01f, 1.0f, 120 | 6.52055535e-01f, 1.93986210e-01f, 4.91611196e-01f, 1.0f, 121 | 6.58483116e-01f, 1.96026835e-01f, 4.90253338e-01f, 1.0f, 122 | 6.64914668e-01f, 1.98075202e-01f, 4.88835712e-01f, 1.0f, 123 | 6.71349279e-01f, 2.00133166e-01f, 4.87357807e-01f, 1.0f, 124 | 6.77785975e-01f, 2.02202663e-01f, 4.85819154e-01f, 1.0f, 125 | 6.84223712e-01f, 2.04285721e-01f, 4.84219325e-01f, 1.0f, 126 | 6.90661380e-01f, 2.06384461e-01f, 4.82557941e-01f, 1.0f, 127 | 6.97097796e-01f, 2.08501100e-01f, 4.80834678e-01f, 1.0f, 128 | 7.03531700e-01f, 2.10637956e-01f, 4.79049270e-01f, 1.0f, 129 | 7.09961888e-01f, 2.12797337e-01f, 4.77201121e-01f, 1.0f, 130 | 7.16387038e-01f, 2.14981693e-01f, 4.75289780e-01f, 1.0f, 131 | 7.22805451e-01f, 2.17193831e-01f, 4.73315708e-01f, 1.0f, 132 | 7.29215521e-01f, 2.19436516e-01f, 4.71278924e-01f, 1.0f, 133 | 7.35615545e-01f, 2.21712634e-01f, 4.69179541e-01f, 1.0f, 134 | 7.42003713e-01f, 2.24025196e-01f, 4.67017774e-01f, 1.0f, 135 | 7.48378107e-01f, 2.26377345e-01f, 4.64793954e-01f, 1.0f, 136 | 7.54736692e-01f, 2.28772352e-01f, 4.62508534e-01f, 1.0f, 137 | 7.61077312e-01f, 2.31213625e-01f, 4.60162106e-01f, 1.0f, 138 | 7.67397681e-01f, 2.33704708e-01f, 4.57755411e-01f, 1.0f, 139 | 7.73695380e-01f, 2.36249283e-01f, 4.55289354e-01f, 1.0f, 140 | 7.79967847e-01f, 2.38851170e-01f, 4.52765022e-01f, 1.0f, 141 | 7.86212372e-01f, 2.41514325e-01f, 4.50183695e-01f, 1.0f, 142 | 7.92426972e-01f, 2.44242250e-01f, 4.47543155e-01f, 1.0f, 143 | 7.98607760e-01f, 2.47039798e-01f, 4.44848441e-01f, 1.0f, 144 | 8.04751511e-01f, 2.49911350e-01f, 4.42101615e-01f, 1.0f, 145 | 8.10854841e-01f, 2.52861399e-01f, 4.39304963e-01f, 1.0f, 146 | 8.16914186e-01f, 2.55894550e-01f, 4.36461074e-01f, 1.0f, 147 | 8.22925797e-01f, 2.59015505e-01f, 4.33572874e-01f, 1.0f, 148 | 8.28885740e-01f, 2.62229049e-01f, 4.30643647e-01f, 1.0f, 149 | 8.34790818e-01f, 2.65539703e-01f, 4.27671352e-01f, 1.0f, 150 | 8.40635680e-01f, 2.68952874e-01f, 4.24665620e-01f, 1.0f, 151 | 8.46415804e-01f, 2.72473491e-01f, 4.21631064e-01f, 1.0f, 152 | 8.52126490e-01f, 2.76106469e-01f, 4.18572767e-01f, 1.0f, 153 | 8.57762870e-01f, 2.79856666e-01f, 4.15496319e-01f, 1.0f, 154 | 8.63320397e-01f, 2.83729003e-01f, 4.12402889e-01f, 1.0f, 155 | 8.68793368e-01f, 2.87728205e-01f, 4.09303002e-01f, 1.0f, 156 | 8.74176342e-01f, 2.91858679e-01f, 4.06205397e-01f, 1.0f, 157 | 8.79463944e-01f, 2.96124596e-01f, 4.03118034e-01f, 1.0f, 158 | 8.84650824e-01f, 3.00530090e-01f, 4.00047060e-01f, 1.0f, 159 | 8.89731418e-01f, 3.05078817e-01f, 3.97001559e-01f, 1.0f, 160 | 8.94700194e-01f, 3.09773445e-01f, 3.93994634e-01f, 1.0f, 161 | 8.99551884e-01f, 3.14616425e-01f, 3.91036674e-01f, 1.0f, 162 | 9.04281297e-01f, 3.19609981e-01f, 3.88136889e-01f, 1.0f, 163 | 9.08883524e-01f, 3.24755126e-01f, 3.85308008e-01f, 1.0f, 164 | 9.13354091e-01f, 3.30051947e-01f, 3.82563414e-01f, 1.0f, 165 | 9.17688852e-01f, 3.35500068e-01f, 3.79915138e-01f, 1.0f, 166 | 9.21884187e-01f, 3.41098112e-01f, 3.77375977e-01f, 1.0f, 167 | 9.25937102e-01f, 3.46843685e-01f, 3.74959077e-01f, 1.0f, 168 | 9.29845090e-01f, 3.52733817e-01f, 3.72676513e-01f, 1.0f, 169 | 9.33606454e-01f, 3.58764377e-01f, 3.70540883e-01f, 1.0f, 170 | 9.37220874e-01f, 3.64929312e-01f, 3.68566525e-01f, 1.0f, 171 | 9.40687443e-01f, 3.71224168e-01f, 3.66761699e-01f, 1.0f, 172 | 9.44006448e-01f, 3.77642889e-01f, 3.65136328e-01f, 1.0f, 173 | 9.47179528e-01f, 3.84177874e-01f, 3.63701130e-01f, 1.0f, 174 | 9.50210150e-01f, 3.90819546e-01f, 3.62467694e-01f, 1.0f, 175 | 9.53099077e-01f, 3.97562894e-01f, 3.61438431e-01f, 1.0f, 176 | 9.55849237e-01f, 4.04400213e-01f, 3.60619076e-01f, 1.0f, 177 | 9.58464079e-01f, 4.11323666e-01f, 3.60014232e-01f, 1.0f, 178 | 9.60949221e-01f, 4.18323245e-01f, 3.59629789e-01f, 1.0f, 179 | 9.63310281e-01f, 4.25389724e-01f, 3.59469020e-01f, 1.0f, 180 | 9.65549351e-01f, 4.32518707e-01f, 3.59529151e-01f, 1.0f, 181 | 9.67671128e-01f, 4.39702976e-01f, 3.59810172e-01f, 1.0f, 182 | 9.69680441e-01f, 4.46935635e-01f, 3.60311120e-01f, 1.0f, 183 | 9.71582181e-01f, 4.54210170e-01f, 3.61030156e-01f, 1.0f, 184 | 9.73381238e-01f, 4.61520484e-01f, 3.61964652e-01f, 1.0f, 185 | 9.75082439e-01f, 4.68860936e-01f, 3.63111292e-01f, 1.0f, 186 | 9.76690494e-01f, 4.76226350e-01f, 3.64466162e-01f, 1.0f, 187 | 9.78209957e-01f, 4.83612031e-01f, 3.66024854e-01f, 1.0f, 188 | 9.79645181e-01f, 4.91013764e-01f, 3.67782559e-01f, 1.0f, 189 | 9.81000291e-01f, 4.98427800e-01f, 3.69734157e-01f, 1.0f, 190 | 9.82279159e-01f, 5.05850848e-01f, 3.71874301e-01f, 1.0f, 191 | 9.83485387e-01f, 5.13280054e-01f, 3.74197501e-01f, 1.0f, 192 | 9.84622298e-01f, 5.20712972e-01f, 3.76698186e-01f, 1.0f, 193 | 9.85692925e-01f, 5.28147545e-01f, 3.79370774e-01f, 1.0f, 194 | 9.86700017e-01f, 5.35582070e-01f, 3.82209724e-01f, 1.0f, 195 | 9.87646038e-01f, 5.43015173e-01f, 3.85209578e-01f, 1.0f, 196 | 9.88533173e-01f, 5.50445778e-01f, 3.88365009e-01f, 1.0f, 197 | 9.89363341e-01f, 5.57873075e-01f, 3.91670846e-01f, 1.0f, 198 | 9.90138201e-01f, 5.65296495e-01f, 3.95122099e-01f, 1.0f, 199 | 9.90871208e-01f, 5.72706259e-01f, 3.98713971e-01f, 1.0f, 200 | 9.91558165e-01f, 5.80106828e-01f, 4.02441058e-01f, 1.0f, 201 | 9.92195728e-01f, 5.87501706e-01f, 4.06298792e-01f, 1.0f, 202 | 9.92784669e-01f, 5.94891088e-01f, 4.10282976e-01f, 1.0f, 203 | 9.93325561e-01f, 6.02275297e-01f, 4.14389658e-01f, 1.0f, 204 | 9.93834412e-01f, 6.09643540e-01f, 4.18613221e-01f, 1.0f, 205 | 9.94308514e-01f, 6.16998953e-01f, 4.22949672e-01f, 1.0f, 206 | 9.94737698e-01f, 6.24349657e-01f, 4.27396771e-01f, 1.0f, 207 | 9.95121854e-01f, 6.31696376e-01f, 4.31951492e-01f, 1.0f, 208 | 9.95480469e-01f, 6.39026596e-01f, 4.36607159e-01f, 1.0f, 209 | 9.95809924e-01f, 6.46343897e-01f, 4.41360951e-01f, 1.0f, 210 | 9.96095703e-01f, 6.53658756e-01f, 4.46213021e-01f, 1.0f, 211 | 9.96341406e-01f, 6.60969379e-01f, 4.51160201e-01f, 1.0f, 212 | 9.96579803e-01f, 6.68255621e-01f, 4.56191814e-01f, 1.0f, 213 | 9.96774784e-01f, 6.75541484e-01f, 4.61314158e-01f, 1.0f, 214 | 9.96925427e-01f, 6.82827953e-01f, 4.66525689e-01f, 1.0f, 215 | 9.97077185e-01f, 6.90087897e-01f, 4.71811461e-01f, 1.0f, 216 | 9.97186253e-01f, 6.97348991e-01f, 4.77181727e-01f, 1.0f, 217 | 9.97253982e-01f, 7.04610791e-01f, 4.82634651e-01f, 1.0f, 218 | 9.97325180e-01f, 7.11847714e-01f, 4.88154375e-01f, 1.0f, 219 | 9.97350983e-01f, 7.19089119e-01f, 4.93754665e-01f, 1.0f, 220 | 9.97350583e-01f, 7.26324415e-01f, 4.99427972e-01f, 1.0f, 221 | 9.97341259e-01f, 7.33544671e-01f, 5.05166839e-01f, 1.0f, 222 | 9.97284689e-01f, 7.40771893e-01f, 5.10983331e-01f, 1.0f, 223 | 9.97228367e-01f, 7.47980563e-01f, 5.16859378e-01f, 1.0f, 224 | 9.97138480e-01f, 7.55189852e-01f, 5.22805996e-01f, 1.0f, 225 | 9.97019342e-01f, 7.62397883e-01f, 5.28820775e-01f, 1.0f, 226 | 9.96898254e-01f, 7.69590975e-01f, 5.34892341e-01f, 1.0f, 227 | 9.96726862e-01f, 7.76794860e-01f, 5.41038571e-01f, 1.0f, 228 | 9.96570645e-01f, 7.83976508e-01f, 5.47232992e-01f, 1.0f, 229 | 9.96369065e-01f, 7.91167346e-01f, 5.53498939e-01f, 1.0f, 230 | 9.96162309e-01f, 7.98347709e-01f, 5.59819643e-01f, 1.0f, 231 | 9.95932448e-01f, 8.05527126e-01f, 5.66201824e-01f, 1.0f, 232 | 9.95680107e-01f, 8.12705773e-01f, 5.72644795e-01f, 1.0f, 233 | 9.95423973e-01f, 8.19875302e-01f, 5.79140130e-01f, 1.0f, 234 | 9.95131288e-01f, 8.27051773e-01f, 5.85701463e-01f, 1.0f, 235 | 9.94851089e-01f, 8.34212826e-01f, 5.92307093e-01f, 1.0f, 236 | 9.94523666e-01f, 8.41386618e-01f, 5.98982818e-01f, 1.0f, 237 | 9.94221900e-01f, 8.48540474e-01f, 6.05695903e-01f, 1.0f, 238 | 9.93865767e-01f, 8.55711038e-01f, 6.12481798e-01f, 1.0f, 239 | 9.93545285e-01f, 8.62858846e-01f, 6.19299300e-01f, 1.0f, 240 | 9.93169558e-01f, 8.70024467e-01f, 6.26189463e-01f, 1.0f, 241 | 9.92830963e-01f, 8.77168404e-01f, 6.33109148e-01f, 1.0f, 242 | 9.92439881e-01f, 8.84329694e-01f, 6.40099465e-01f, 1.0f, 243 | 9.92089454e-01f, 8.91469549e-01f, 6.47116021e-01f, 1.0f, 244 | 9.91687744e-01f, 8.98627050e-01f, 6.54201544e-01f, 1.0f, 245 | 9.91331929e-01f, 9.05762748e-01f, 6.61308839e-01f, 1.0f, 246 | 9.90929685e-01f, 9.12915010e-01f, 6.68481201e-01f, 1.0f, 247 | 9.90569914e-01f, 9.20048699e-01f, 6.75674592e-01f, 1.0f, 248 | 9.90174637e-01f, 9.27195612e-01f, 6.82925602e-01f, 1.0f, 249 | 9.89814839e-01f, 9.34328540e-01f, 6.90198194e-01f, 1.0f, 250 | 9.89433736e-01f, 9.41470354e-01f, 6.97518628e-01f, 1.0f, 251 | 9.89077438e-01f, 9.48604077e-01f, 7.04862519e-01f, 1.0f, 252 | 9.88717064e-01f, 9.55741520e-01f, 7.12242232e-01f, 1.0f, 253 | 9.88367028e-01f, 9.62878026e-01f, 7.19648627e-01f, 1.0f, 254 | 9.88032885e-01f, 9.70012413e-01f, 7.27076773e-01f, 1.0f, 255 | 9.87690702e-01f, 9.77154231e-01f, 7.34536205e-01f, 1.0f, 256 | 9.87386827e-01f, 9.84287561e-01f, 7.42001547e-01f, 1.0f, 257 | 9.87052509e-01f, 9.91437853e-01f, 7.49504188e-01f, 1.0f 258 | }; 259 | const int colormap_inferno_length = sizeof(colormap_inferno)/sizeof(colormap_inferno[0])/4; 260 | --------------------------------------------------------------------------------