<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://vegard.wiki/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Vegard</id>
	<title>vegard.wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://vegard.wiki/mediawiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Vegard"/>
	<link rel="alternate" type="text/html" href="http://vegard.wiki/w/Special:Contributions/Vegard"/>
	<updated>2026-07-04T13:37:23Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=346</id>
		<title>GLSL snippets</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=346"/>
		<updated>2024-04-09T09:03:45Z</updated>

		<summary type="html">&lt;p&gt;Vegard: /* Colours */ blue ice gradient&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Signed distance functions ==&lt;br /&gt;
&lt;br /&gt;
=== Antialiasing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float scale = 100.;&lt;br /&gt;
&lt;br /&gt;
void mainImage( out vec4 fragColor, in vec2 fragCoord )&lt;br /&gt;
{&lt;br /&gt;
    vec2 uv = scale * (fragCoord - .5 * iResolution.xy) / iResolution.y;&lt;br /&gt;
    float d = sd...(uv);&lt;br /&gt;
    vec3 col = vec3(1) * smoothstep(-0., 1.5 * scale / iResolution.y, d);&lt;br /&gt;
    fragColor = vec4(col, 1.);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The point here is to convert the length returned by the distance function into a number of pixels, and then we can smooth the outline over the precise number of pixels that we want (here 1.5).&lt;br /&gt;
&lt;br /&gt;
== Ray marching ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {&lt;br /&gt;
    vec2 xy = fragCoord - size / 2.;&lt;br /&gt;
    float z = size.y / tan(radians(fieldOfView) / 2.) / 2.;&lt;br /&gt;
    return normalize(vec3(xy, -z));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: The original &amp;lt;tt&amp;gt;rayDirection()&amp;lt;/tt&amp;gt; is missing the divide by 2 when calculating z. This causes the field of view parameter to be incorrect.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
float castRay(const int scene, vec3 eye, vec3 dir,&lt;br /&gt;
    float start, float end, float epsilon, int max_marching_steps,&lt;br /&gt;
    out int material)&lt;br /&gt;
{&lt;br /&gt;
    float depth = start;&lt;br /&gt;
    for (int i = 0; i &amp;lt; max_marching_steps; i++) {&lt;br /&gt;
        float d = sceneSDF(scene, eye + depth * dir, material);&lt;br /&gt;
        if (d &amp;lt; epsilon)&lt;br /&gt;
            return depth;&lt;br /&gt;
&lt;br /&gt;
        depth += d;&lt;br /&gt;
        if (depth &amp;gt;= end)&lt;br /&gt;
            break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return end;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm&lt;br /&gt;
vec3 estimateNormal( const int scene, const float epsilon, in vec3 p )&lt;br /&gt;
{&lt;br /&gt;
    int m;&lt;br /&gt;
    &lt;br /&gt;
    const vec2 k = vec2(1,-1);&lt;br /&gt;
    return normalize( k.xyy*sceneSDF( scene, p + k.xyy*epsilon, m ) + &lt;br /&gt;
                      k.yyx*sceneSDF( scene, p + k.yyx*epsilon, m ) + &lt;br /&gt;
                      k.yxy*sceneSDF( scene, p + k.yxy*epsilon, m ) + &lt;br /&gt;
                      k.xxx*sceneSDF( scene, p + k.xxx*epsilon, m ) );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Matrix transformations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml&lt;br /&gt;
mat4 rotate(float a, vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    float c = cos(a);&lt;br /&gt;
    vec3 ci = (1. - c) * v;&lt;br /&gt;
    vec3 s = sin(a) * v;&lt;br /&gt;
&lt;br /&gt;
    return mat4(&lt;br /&gt;
        ci.x * v.x + c, ci.x * v.y + s.z, ci.x * v.z - s.y, 0,&lt;br /&gt;
        ci.y * v.x - s.z, ci.y * v.y + c, ci.y * v.z + s.x, 0,&lt;br /&gt;
        ci.z * v.x + s.y, ci.z * v.y - s.x, ci.z * v.z + c, 0,&lt;br /&gt;
        0, 0, 0, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml&lt;br /&gt;
mat4 translate(vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    return mat4(&lt;br /&gt;
        1, 0, 0, 0,&lt;br /&gt;
        0, 1, 0, 0,&lt;br /&gt;
        0, 0, 1, 0,&lt;br /&gt;
        v.x, v.y, v.z, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Noise ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner&lt;br /&gt;
float rand(vec2 co)&lt;br /&gt;
{&lt;br /&gt;
    return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Colours ==&lt;br /&gt;
&lt;br /&gt;
=== HSV ===&lt;br /&gt;
&lt;br /&gt;
==== Plain HSV ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://github.com/hughsk/glsl-hsv2rgb/blob/master/index.glsl&lt;br /&gt;
vec3 hsv2rgb(vec3 c) {&lt;br /&gt;
    vec4 K = vec4(3. / 3., 2. / 3., 1. / 3., 3.);&lt;br /&gt;
    vec3 p = abs(fract(c.xxx + K.xyz) * 6. - K.www);&lt;br /&gt;
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Smooth variant ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb2.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb2()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.shadertoy.com/view/wlsSRB&lt;br /&gt;
vec3 hsv2rgb2(vec3 c, float k) {&lt;br /&gt;
    vec4 K = vec4(3. / 3., 2. / 3., 1. / 3., 3.);&lt;br /&gt;
    vec3 p = smoothstep(0. + k, 1. - k,&lt;br /&gt;
        .5 + .5 * cos((c.xxx + K.xyz) * radians(360.)));&lt;br /&gt;
    return c.z * mix(K.xxx, p, c.y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A good value for &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; is e.g. 0.07.&lt;br /&gt;
&lt;br /&gt;
=== Gamma ===&lt;br /&gt;
&lt;br /&gt;
{{Main|Gamma}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float gamma = 2.2;&lt;br /&gt;
&lt;br /&gt;
// convert from sRGB to RGB&lt;br /&gt;
vec3 col = pow(col, vec3(gamma));&lt;br /&gt;
&lt;br /&gt;
// blending, etc.&lt;br /&gt;
&lt;br /&gt;
// gamma correction (RGB to sRGB)&lt;br /&gt;
col = pow(col, vec3(1. / gamma));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ice gradient ===&lt;br /&gt;
&lt;br /&gt;
[[File:ice_gradient.png|420px|thumb|Blue ice gradient]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
vec3 col = smoothstep(vec3(.2, .1, .0), vec3(1.2, 1.1, 1.0), vec3(x));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dithering ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
/* https://en.wikipedia.org/wiki/Ordered_dithering */&lt;br /&gt;
const float bayer_matrix[64] = float[64](&lt;br /&gt;
     -0.500000,  0.250000, -0.312500,  0.437500, -0.453125,  0.296875, -0.265625,  0.484375,&lt;br /&gt;
      0.000000, -0.250000,  0.187500, -0.062500,  0.046875, -0.203125,  0.234375, -0.015625,&lt;br /&gt;
     -0.375000,  0.375000, -0.437500,  0.312500, -0.328125,  0.421875, -0.390625,  0.359375,&lt;br /&gt;
      0.125000, -0.125000,  0.062500, -0.187500,  0.171875, -0.078125,  0.109375, -0.140625,&lt;br /&gt;
     -0.468750,  0.281250, -0.281250,  0.468750, -0.484375,  0.265625, -0.296875,  0.453125,&lt;br /&gt;
      0.031250, -0.218750,  0.218750, -0.031250,  0.015625, -0.234375,  0.203125, -0.046875,&lt;br /&gt;
     -0.343750,  0.406250, -0.406250,  0.343750, -0.359375,  0.390625, -0.421875,  0.328125,&lt;br /&gt;
      0.156250, -0.093750,  0.093750, -0.156250,  0.140625, -0.109375,  0.078125, -0.171875&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
float dither(vec2 uv, float levels, float sharpness, float intensity)&lt;br /&gt;
{&lt;br /&gt;
    int x = int(floor(uv.x)) &amp;amp; 7;&lt;br /&gt;
    int y = int(floor(uv.y)) &amp;amp; 7;&lt;br /&gt;
    float threshold = bayer_matrix[8 * y + x];&lt;br /&gt;
#if 0 // full dither&lt;br /&gt;
    return round(levels * intensity + threshold) / levels;&lt;br /&gt;
#else // respect sharpness&lt;br /&gt;
    float major = floor(levels * intensity);&lt;br /&gt;
    float minor = float(fract(levels * intensity) &amp;gt; .5 + sharpness * threshold);&lt;br /&gt;
    return (major + minor) / levels;&lt;br /&gt;
#endif&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Post-processing effects ==&lt;br /&gt;
&lt;br /&gt;
=== Volumetric light scattering (God rays) ===&lt;br /&gt;
&lt;br /&gt;
[[File:godrays.png|420px|thumb|Example of volumetric light scattering post-processing effect (with dithering).]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-13-volumetric-light-scattering-post-process&lt;br /&gt;
vec3 godrays(in vec2 ScreenLightPos, in vec2 fragCoord, out vec4 fragColor)&lt;br /&gt;
{&lt;br /&gt;
    const int NUM_SAMPLES = 16;&lt;br /&gt;
    const float Density = .7;&lt;br /&gt;
    const float Weight = .3;&lt;br /&gt;
    const float Decay = .88;&lt;br /&gt;
    const float Exposure = .4;&lt;br /&gt;
&lt;br /&gt;
    vec2 texCoord = fragCoord / iResolution.xy;&lt;br /&gt;
    vec2 deltaTexCoord = (texCoord - ScreenLightPos.xy);&lt;br /&gt;
    deltaTexCoord *= 1.0f / float(NUM_SAMPLES) * Density;&lt;br /&gt;
&lt;br /&gt;
    vec3 color = texture(iChannel0, texCoord).rgb;&lt;br /&gt;
    float illuminationDecay = 1.0f;&lt;br /&gt;
&lt;br /&gt;
    for (int i = 0; i &amp;lt; NUM_SAMPLES; i++) {&lt;br /&gt;
        texCoord -= deltaTexCoord;&lt;br /&gt;
&lt;br /&gt;
        float dither = rand(fragCoord + vec2(200. * float(i), 23. * float(i)));&lt;br /&gt;
        vec3 sample_ = texture(iChannel0, texCoord + deltaTexCoord * dither).rgb;&lt;br /&gt;
        sample_ *= illuminationDecay * Weight;&lt;br /&gt;
        color += sample_;&lt;br /&gt;
        illuminationDecay *= Decay;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return color * Exposure;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dithering suggested by Jessica Mak.&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=File:ice_gradient.png&amp;diff=345</id>
		<title>File:ice gradient.png</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=File:ice_gradient.png&amp;diff=345"/>
		<updated>2024-04-09T09:02:56Z</updated>

		<summary type="html">&lt;p&gt;Vegard: Blue ice gradient&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Blue ice gradient&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Tone_mapping&amp;diff=344</id>
		<title>Tone mapping</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Tone_mapping&amp;diff=344"/>
		<updated>2022-12-20T21:55:51Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add ref&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
My own formula (https://www.shadertoy.com/view/Dlf3RM):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
mix(v, vec3(1.), smoothstep(1., 4., dot(v, vec3(1.))));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* https://learnopengl.com/Advanced-Lighting/HDR&lt;br /&gt;
* http://filmicworlds.com/blog/filmic-tonemapping-operators/&lt;br /&gt;
* https://64.github.io/tonemapping/&lt;br /&gt;
* https://mynameismjp.wordpress.com/2010/04/30/a-closer-look-at-tone-mapping/&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Tone_mapping&amp;diff=343</id>
		<title>Tone mapping</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Tone_mapping&amp;diff=343"/>
		<updated>2022-12-19T16:52:14Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add my formula + reference&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
My own formula (https://www.shadertoy.com/view/Dlf3RM):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
mix(v, vec3(1.), smoothstep(1., 4., dot(v, vec3(1.))));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* https://learnopengl.com/Advanced-Lighting/HDR&lt;br /&gt;
* http://filmicworlds.com/blog/filmic-tonemapping-operators/&lt;br /&gt;
* https://64.github.io/tonemapping/&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=342</id>
		<title>GLSL snippets</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=342"/>
		<updated>2022-12-08T13:18:48Z</updated>

		<summary type="html">&lt;p&gt;Vegard: /* Smooth variant */ fix again&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Signed distance functions ==&lt;br /&gt;
&lt;br /&gt;
=== Antialiasing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float scale = 100.;&lt;br /&gt;
&lt;br /&gt;
void mainImage( out vec4 fragColor, in vec2 fragCoord )&lt;br /&gt;
{&lt;br /&gt;
    vec2 uv = scale * (fragCoord - .5 * iResolution.xy) / iResolution.y;&lt;br /&gt;
    float d = sd...(uv);&lt;br /&gt;
    vec3 col = vec3(1) * smoothstep(-0., 1.5 * scale / iResolution.y, d);&lt;br /&gt;
    fragColor = vec4(col, 1.);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The point here is to convert the length returned by the distance function into a number of pixels, and then we can smooth the outline over the precise number of pixels that we want (here 1.5).&lt;br /&gt;
&lt;br /&gt;
== Ray marching ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {&lt;br /&gt;
    vec2 xy = fragCoord - size / 2.;&lt;br /&gt;
    float z = size.y / tan(radians(fieldOfView) / 2.) / 2.;&lt;br /&gt;
    return normalize(vec3(xy, -z));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: The original &amp;lt;tt&amp;gt;rayDirection()&amp;lt;/tt&amp;gt; is missing the divide by 2 when calculating z. This causes the field of view parameter to be incorrect.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
float castRay(const int scene, vec3 eye, vec3 dir,&lt;br /&gt;
    float start, float end, float epsilon, int max_marching_steps,&lt;br /&gt;
    out int material)&lt;br /&gt;
{&lt;br /&gt;
    float depth = start;&lt;br /&gt;
    for (int i = 0; i &amp;lt; max_marching_steps; i++) {&lt;br /&gt;
        float d = sceneSDF(scene, eye + depth * dir, material);&lt;br /&gt;
        if (d &amp;lt; epsilon)&lt;br /&gt;
            return depth;&lt;br /&gt;
&lt;br /&gt;
        depth += d;&lt;br /&gt;
        if (depth &amp;gt;= end)&lt;br /&gt;
            break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return end;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm&lt;br /&gt;
vec3 estimateNormal( const int scene, const float epsilon, in vec3 p )&lt;br /&gt;
{&lt;br /&gt;
    int m;&lt;br /&gt;
    &lt;br /&gt;
    const vec2 k = vec2(1,-1);&lt;br /&gt;
    return normalize( k.xyy*sceneSDF( scene, p + k.xyy*epsilon, m ) + &lt;br /&gt;
                      k.yyx*sceneSDF( scene, p + k.yyx*epsilon, m ) + &lt;br /&gt;
                      k.yxy*sceneSDF( scene, p + k.yxy*epsilon, m ) + &lt;br /&gt;
                      k.xxx*sceneSDF( scene, p + k.xxx*epsilon, m ) );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Matrix transformations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml&lt;br /&gt;
mat4 rotate(float a, vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    float c = cos(a);&lt;br /&gt;
    vec3 ci = (1. - c) * v;&lt;br /&gt;
    vec3 s = sin(a) * v;&lt;br /&gt;
&lt;br /&gt;
    return mat4(&lt;br /&gt;
        ci.x * v.x + c, ci.x * v.y + s.z, ci.x * v.z - s.y, 0,&lt;br /&gt;
        ci.y * v.x - s.z, ci.y * v.y + c, ci.y * v.z + s.x, 0,&lt;br /&gt;
        ci.z * v.x + s.y, ci.z * v.y - s.x, ci.z * v.z + c, 0,&lt;br /&gt;
        0, 0, 0, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml&lt;br /&gt;
mat4 translate(vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    return mat4(&lt;br /&gt;
        1, 0, 0, 0,&lt;br /&gt;
        0, 1, 0, 0,&lt;br /&gt;
        0, 0, 1, 0,&lt;br /&gt;
        v.x, v.y, v.z, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Noise ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner&lt;br /&gt;
float rand(vec2 co)&lt;br /&gt;
{&lt;br /&gt;
    return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Colours ==&lt;br /&gt;
&lt;br /&gt;
=== HSV ===&lt;br /&gt;
&lt;br /&gt;
==== Plain HSV ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://github.com/hughsk/glsl-hsv2rgb/blob/master/index.glsl&lt;br /&gt;
vec3 hsv2rgb(vec3 c) {&lt;br /&gt;
    vec4 K = vec4(3. / 3., 2. / 3., 1. / 3., 3.);&lt;br /&gt;
    vec3 p = abs(fract(c.xxx + K.xyz) * 6. - K.www);&lt;br /&gt;
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Smooth variant ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb2.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb2()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.shadertoy.com/view/wlsSRB&lt;br /&gt;
vec3 hsv2rgb2(vec3 c, float k) {&lt;br /&gt;
    vec4 K = vec4(3. / 3., 2. / 3., 1. / 3., 3.);&lt;br /&gt;
    vec3 p = smoothstep(0. + k, 1. - k,&lt;br /&gt;
        .5 + .5 * cos((c.xxx + K.xyz) * radians(360.)));&lt;br /&gt;
    return c.z * mix(K.xxx, p, c.y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A good value for &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; is e.g. 0.07.&lt;br /&gt;
&lt;br /&gt;
=== Gamma ===&lt;br /&gt;
&lt;br /&gt;
{{Main|Gamma}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float gamma = 2.2;&lt;br /&gt;
&lt;br /&gt;
// convert from sRGB to RGB&lt;br /&gt;
vec3 col = pow(col, vec3(gamma));&lt;br /&gt;
&lt;br /&gt;
// blending, etc.&lt;br /&gt;
&lt;br /&gt;
// gamma correction (RGB to sRGB)&lt;br /&gt;
col = pow(col, vec3(1. / gamma));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dithering ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
/* https://en.wikipedia.org/wiki/Ordered_dithering */&lt;br /&gt;
const float bayer_matrix[64] = float[64](&lt;br /&gt;
     -0.500000,  0.250000, -0.312500,  0.437500, -0.453125,  0.296875, -0.265625,  0.484375,&lt;br /&gt;
      0.000000, -0.250000,  0.187500, -0.062500,  0.046875, -0.203125,  0.234375, -0.015625,&lt;br /&gt;
     -0.375000,  0.375000, -0.437500,  0.312500, -0.328125,  0.421875, -0.390625,  0.359375,&lt;br /&gt;
      0.125000, -0.125000,  0.062500, -0.187500,  0.171875, -0.078125,  0.109375, -0.140625,&lt;br /&gt;
     -0.468750,  0.281250, -0.281250,  0.468750, -0.484375,  0.265625, -0.296875,  0.453125,&lt;br /&gt;
      0.031250, -0.218750,  0.218750, -0.031250,  0.015625, -0.234375,  0.203125, -0.046875,&lt;br /&gt;
     -0.343750,  0.406250, -0.406250,  0.343750, -0.359375,  0.390625, -0.421875,  0.328125,&lt;br /&gt;
      0.156250, -0.093750,  0.093750, -0.156250,  0.140625, -0.109375,  0.078125, -0.171875&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
float dither(vec2 uv, float levels, float sharpness, float intensity)&lt;br /&gt;
{&lt;br /&gt;
    int x = int(floor(uv.x)) &amp;amp; 7;&lt;br /&gt;
    int y = int(floor(uv.y)) &amp;amp; 7;&lt;br /&gt;
    float threshold = bayer_matrix[8 * y + x];&lt;br /&gt;
#if 0 // full dither&lt;br /&gt;
    return round(levels * intensity + threshold) / levels;&lt;br /&gt;
#else // respect sharpness&lt;br /&gt;
    float major = floor(levels * intensity);&lt;br /&gt;
    float minor = float(fract(levels * intensity) &amp;gt; .5 + sharpness * threshold);&lt;br /&gt;
    return (major + minor) / levels;&lt;br /&gt;
#endif&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Post-processing effects ==&lt;br /&gt;
&lt;br /&gt;
=== Volumetric light scattering (God rays) ===&lt;br /&gt;
&lt;br /&gt;
[[File:godrays.png|420px|thumb|Example of volumetric light scattering post-processing effect (with dithering).]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-13-volumetric-light-scattering-post-process&lt;br /&gt;
vec3 godrays(in vec2 ScreenLightPos, in vec2 fragCoord, out vec4 fragColor)&lt;br /&gt;
{&lt;br /&gt;
    const int NUM_SAMPLES = 16;&lt;br /&gt;
    const float Density = .7;&lt;br /&gt;
    const float Weight = .3;&lt;br /&gt;
    const float Decay = .88;&lt;br /&gt;
    const float Exposure = .4;&lt;br /&gt;
&lt;br /&gt;
    vec2 texCoord = fragCoord / iResolution.xy;&lt;br /&gt;
    vec2 deltaTexCoord = (texCoord - ScreenLightPos.xy);&lt;br /&gt;
    deltaTexCoord *= 1.0f / float(NUM_SAMPLES) * Density;&lt;br /&gt;
&lt;br /&gt;
    vec3 color = texture(iChannel0, texCoord).rgb;&lt;br /&gt;
    float illuminationDecay = 1.0f;&lt;br /&gt;
&lt;br /&gt;
    for (int i = 0; i &amp;lt; NUM_SAMPLES; i++) {&lt;br /&gt;
        texCoord -= deltaTexCoord;&lt;br /&gt;
&lt;br /&gt;
        float dither = rand(fragCoord + vec2(200. * float(i), 23. * float(i)));&lt;br /&gt;
        vec3 sample_ = texture(iChannel0, texCoord + deltaTexCoord * dither).rgb;&lt;br /&gt;
        sample_ *= illuminationDecay * Weight;&lt;br /&gt;
        color += sample_;&lt;br /&gt;
        illuminationDecay *= Decay;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return color * Exposure;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dithering suggested by Jessica Mak.&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=341</id>
		<title>GLSL snippets</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=341"/>
		<updated>2022-12-08T13:14:09Z</updated>

		<summary type="html">&lt;p&gt;Vegard: /* Smooth variant */ fix saturation/value&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Signed distance functions ==&lt;br /&gt;
&lt;br /&gt;
=== Antialiasing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float scale = 100.;&lt;br /&gt;
&lt;br /&gt;
void mainImage( out vec4 fragColor, in vec2 fragCoord )&lt;br /&gt;
{&lt;br /&gt;
    vec2 uv = scale * (fragCoord - .5 * iResolution.xy) / iResolution.y;&lt;br /&gt;
    float d = sd...(uv);&lt;br /&gt;
    vec3 col = vec3(1) * smoothstep(-0., 1.5 * scale / iResolution.y, d);&lt;br /&gt;
    fragColor = vec4(col, 1.);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The point here is to convert the length returned by the distance function into a number of pixels, and then we can smooth the outline over the precise number of pixels that we want (here 1.5).&lt;br /&gt;
&lt;br /&gt;
== Ray marching ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {&lt;br /&gt;
    vec2 xy = fragCoord - size / 2.;&lt;br /&gt;
    float z = size.y / tan(radians(fieldOfView) / 2.) / 2.;&lt;br /&gt;
    return normalize(vec3(xy, -z));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: The original &amp;lt;tt&amp;gt;rayDirection()&amp;lt;/tt&amp;gt; is missing the divide by 2 when calculating z. This causes the field of view parameter to be incorrect.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
float castRay(const int scene, vec3 eye, vec3 dir,&lt;br /&gt;
    float start, float end, float epsilon, int max_marching_steps,&lt;br /&gt;
    out int material)&lt;br /&gt;
{&lt;br /&gt;
    float depth = start;&lt;br /&gt;
    for (int i = 0; i &amp;lt; max_marching_steps; i++) {&lt;br /&gt;
        float d = sceneSDF(scene, eye + depth * dir, material);&lt;br /&gt;
        if (d &amp;lt; epsilon)&lt;br /&gt;
            return depth;&lt;br /&gt;
&lt;br /&gt;
        depth += d;&lt;br /&gt;
        if (depth &amp;gt;= end)&lt;br /&gt;
            break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return end;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm&lt;br /&gt;
vec3 estimateNormal( const int scene, const float epsilon, in vec3 p )&lt;br /&gt;
{&lt;br /&gt;
    int m;&lt;br /&gt;
    &lt;br /&gt;
    const vec2 k = vec2(1,-1);&lt;br /&gt;
    return normalize( k.xyy*sceneSDF( scene, p + k.xyy*epsilon, m ) + &lt;br /&gt;
                      k.yyx*sceneSDF( scene, p + k.yyx*epsilon, m ) + &lt;br /&gt;
                      k.yxy*sceneSDF( scene, p + k.yxy*epsilon, m ) + &lt;br /&gt;
                      k.xxx*sceneSDF( scene, p + k.xxx*epsilon, m ) );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Matrix transformations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml&lt;br /&gt;
mat4 rotate(float a, vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    float c = cos(a);&lt;br /&gt;
    vec3 ci = (1. - c) * v;&lt;br /&gt;
    vec3 s = sin(a) * v;&lt;br /&gt;
&lt;br /&gt;
    return mat4(&lt;br /&gt;
        ci.x * v.x + c, ci.x * v.y + s.z, ci.x * v.z - s.y, 0,&lt;br /&gt;
        ci.y * v.x - s.z, ci.y * v.y + c, ci.y * v.z + s.x, 0,&lt;br /&gt;
        ci.z * v.x + s.y, ci.z * v.y - s.x, ci.z * v.z + c, 0,&lt;br /&gt;
        0, 0, 0, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml&lt;br /&gt;
mat4 translate(vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    return mat4(&lt;br /&gt;
        1, 0, 0, 0,&lt;br /&gt;
        0, 1, 0, 0,&lt;br /&gt;
        0, 0, 1, 0,&lt;br /&gt;
        v.x, v.y, v.z, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Noise ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner&lt;br /&gt;
float rand(vec2 co)&lt;br /&gt;
{&lt;br /&gt;
    return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Colours ==&lt;br /&gt;
&lt;br /&gt;
=== HSV ===&lt;br /&gt;
&lt;br /&gt;
==== Plain HSV ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://github.com/hughsk/glsl-hsv2rgb/blob/master/index.glsl&lt;br /&gt;
vec3 hsv2rgb(vec3 c) {&lt;br /&gt;
    vec4 K = vec4(3. / 3., 2. / 3., 1. / 3., 3.);&lt;br /&gt;
    vec3 p = abs(fract(c.xxx + K.xyz) * 6. - K.www);&lt;br /&gt;
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Smooth variant ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb2.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb2()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.shadertoy.com/view/wlsSRB&lt;br /&gt;
vec3 hsv2rgb2(vec3 c, float k) {&lt;br /&gt;
    vec4 K = vec4(3. / 3., 2. / 3., 1. / 3., 3.);&lt;br /&gt;
    vec3 p = smoothstep(0. + k, 1. - k,&lt;br /&gt;
        .5 + .5 * cos((c.xxx + K.xyz) * radians(360.)));&lt;br /&gt;
    return c.z * mix(K.www, p, c.y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A good value for &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; is e.g. 0.07.&lt;br /&gt;
&lt;br /&gt;
=== Gamma ===&lt;br /&gt;
&lt;br /&gt;
{{Main|Gamma}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float gamma = 2.2;&lt;br /&gt;
&lt;br /&gt;
// convert from sRGB to RGB&lt;br /&gt;
vec3 col = pow(col, vec3(gamma));&lt;br /&gt;
&lt;br /&gt;
// blending, etc.&lt;br /&gt;
&lt;br /&gt;
// gamma correction (RGB to sRGB)&lt;br /&gt;
col = pow(col, vec3(1. / gamma));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dithering ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
/* https://en.wikipedia.org/wiki/Ordered_dithering */&lt;br /&gt;
const float bayer_matrix[64] = float[64](&lt;br /&gt;
     -0.500000,  0.250000, -0.312500,  0.437500, -0.453125,  0.296875, -0.265625,  0.484375,&lt;br /&gt;
      0.000000, -0.250000,  0.187500, -0.062500,  0.046875, -0.203125,  0.234375, -0.015625,&lt;br /&gt;
     -0.375000,  0.375000, -0.437500,  0.312500, -0.328125,  0.421875, -0.390625,  0.359375,&lt;br /&gt;
      0.125000, -0.125000,  0.062500, -0.187500,  0.171875, -0.078125,  0.109375, -0.140625,&lt;br /&gt;
     -0.468750,  0.281250, -0.281250,  0.468750, -0.484375,  0.265625, -0.296875,  0.453125,&lt;br /&gt;
      0.031250, -0.218750,  0.218750, -0.031250,  0.015625, -0.234375,  0.203125, -0.046875,&lt;br /&gt;
     -0.343750,  0.406250, -0.406250,  0.343750, -0.359375,  0.390625, -0.421875,  0.328125,&lt;br /&gt;
      0.156250, -0.093750,  0.093750, -0.156250,  0.140625, -0.109375,  0.078125, -0.171875&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
float dither(vec2 uv, float levels, float sharpness, float intensity)&lt;br /&gt;
{&lt;br /&gt;
    int x = int(floor(uv.x)) &amp;amp; 7;&lt;br /&gt;
    int y = int(floor(uv.y)) &amp;amp; 7;&lt;br /&gt;
    float threshold = bayer_matrix[8 * y + x];&lt;br /&gt;
#if 0 // full dither&lt;br /&gt;
    return round(levels * intensity + threshold) / levels;&lt;br /&gt;
#else // respect sharpness&lt;br /&gt;
    float major = floor(levels * intensity);&lt;br /&gt;
    float minor = float(fract(levels * intensity) &amp;gt; .5 + sharpness * threshold);&lt;br /&gt;
    return (major + minor) / levels;&lt;br /&gt;
#endif&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Post-processing effects ==&lt;br /&gt;
&lt;br /&gt;
=== Volumetric light scattering (God rays) ===&lt;br /&gt;
&lt;br /&gt;
[[File:godrays.png|420px|thumb|Example of volumetric light scattering post-processing effect (with dithering).]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-13-volumetric-light-scattering-post-process&lt;br /&gt;
vec3 godrays(in vec2 ScreenLightPos, in vec2 fragCoord, out vec4 fragColor)&lt;br /&gt;
{&lt;br /&gt;
    const int NUM_SAMPLES = 16;&lt;br /&gt;
    const float Density = .7;&lt;br /&gt;
    const float Weight = .3;&lt;br /&gt;
    const float Decay = .88;&lt;br /&gt;
    const float Exposure = .4;&lt;br /&gt;
&lt;br /&gt;
    vec2 texCoord = fragCoord / iResolution.xy;&lt;br /&gt;
    vec2 deltaTexCoord = (texCoord - ScreenLightPos.xy);&lt;br /&gt;
    deltaTexCoord *= 1.0f / float(NUM_SAMPLES) * Density;&lt;br /&gt;
&lt;br /&gt;
    vec3 color = texture(iChannel0, texCoord).rgb;&lt;br /&gt;
    float illuminationDecay = 1.0f;&lt;br /&gt;
&lt;br /&gt;
    for (int i = 0; i &amp;lt; NUM_SAMPLES; i++) {&lt;br /&gt;
        texCoord -= deltaTexCoord;&lt;br /&gt;
&lt;br /&gt;
        float dither = rand(fragCoord + vec2(200. * float(i), 23. * float(i)));&lt;br /&gt;
        vec3 sample_ = texture(iChannel0, texCoord + deltaTexCoord * dither).rgb;&lt;br /&gt;
        sample_ *= illuminationDecay * Weight;&lt;br /&gt;
        color += sample_;&lt;br /&gt;
        illuminationDecay *= Decay;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return color * Exposure;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dithering suggested by Jessica Mak.&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=User:Vegard/Profiles&amp;diff=340</id>
		<title>User:Vegard/Profiles</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=User:Vegard/Profiles&amp;diff=340"/>
		<updated>2022-11-30T07:34:24Z</updated>

		<summary type="html">&lt;p&gt;Vegard: Twitter -&amp;gt; Mastodon&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;-moz-column-width: 30em; -webkit-column-width: 30em; column-width: 30em;&amp;quot;&amp;gt;&lt;br /&gt;
* Mastodon: https://mastodon.social/@vegard&lt;br /&gt;
* Blog: http://www.vegardno.net/&lt;br /&gt;
* GitHub: https://github.com/vegard/&lt;br /&gt;
* Shadertoy: https://www.shadertoy.com/user/vegardno&lt;br /&gt;
* Keybase: https://keybase.io/vegardno&lt;br /&gt;
* E-mail: &amp;lt;tt&amp;gt;vegard.nossum@gmail.com&amp;lt;/tt&amp;gt;&lt;br /&gt;
* &amp;lt;del&amp;gt;Twitter: https://twitter.com/vegard_no&amp;lt;/del&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=SSE_routines&amp;diff=339</id>
		<title>SSE routines</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=SSE_routines&amp;diff=339"/>
		<updated>2022-11-22T08:54:26Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add link from saidwho12&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=== Boilerplate ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;emmintrin.h&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Get length of string prefix consisting of letters and underscore ===&lt;br /&gt;
&lt;br /&gt;
This can be useful for e.g. parsing identifiers.&lt;br /&gt;
&lt;br /&gt;
The string does not need to be aligned, but beware that up to 15 bytes after the NUL terminator may be loaded from memory, so if these cross a page boundary you can get spurious page faults.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
int nr_alpha(const char *s)&lt;br /&gt;
{&lt;br /&gt;
    const char *start = s;&lt;br /&gt;
    &lt;br /&gt;
    __m128i ch_A = _mm_set1_epi8(&#039;A&#039; - 1);&lt;br /&gt;
    __m128i ch_Z = _mm_set1_epi8(&#039;Z&#039;);&lt;br /&gt;
    __m128i ch_underscore = _mm_set1_epi8(&#039;_&#039;);&lt;br /&gt;
&lt;br /&gt;
    while (1) {&lt;br /&gt;
        __m128i ch = _mm_loadu_si128((__m128i *) s);&lt;br /&gt;
        __m128i b = _mm_and_si128(ch, _mm_set1_epi8(~0x20));&lt;br /&gt;
        b = _mm_or_si128(_mm_and_si128(_mm_cmpgt_epi8(b, ch_A),&lt;br /&gt;
                                       _mm_cmplt_epi8(b, ch_Z)),&lt;br /&gt;
                         _mm_cmpeq_epi8(ch, ch_underscore));&lt;br /&gt;
&lt;br /&gt;
        unsigned int ffs = __builtin_ffs(~_mm_movemask_epi8(b)) - 1;&lt;br /&gt;
        s += ffs;&lt;br /&gt;
&lt;br /&gt;
        if (ffs &amp;lt; 16)&lt;br /&gt;
            return s - start;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Get length of string prefix consisting of whitespace ===&lt;br /&gt;
&lt;br /&gt;
(See caveats above.)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
int nr_whitespace(const char *s)&lt;br /&gt;
{&lt;br /&gt;
    const char *start = s;&lt;br /&gt;
&lt;br /&gt;
    while (1) {&lt;br /&gt;
        __m128i ch = _mm_loadu_si128((__m128i *) s);&lt;br /&gt;
        __m128i b = _mm_or_si128(_mm_cmpeq_epi8(ch, _mm_set1_epi8(&#039; &#039;)),&lt;br /&gt;
                                 _mm_cmpeq_epi8(ch, _mm_set1_epi8(&#039;\t&#039;)));&lt;br /&gt;
        b = _mm_or_si128(b, _mm_cmpeq_epi8(ch, _mm_set1_epi8(&#039;\r&#039;)));&lt;br /&gt;
        b = _mm_or_si128(b, _mm_cmpeq_epi8(ch, _mm_set1_epi8(&#039;\n&#039;)));&lt;br /&gt;
&lt;br /&gt;
        unsigned int ffs = __builtin_ffs(~_mm_movemask_epi8(b)) - 1;&lt;br /&gt;
        s += ffs;&lt;br /&gt;
&lt;br /&gt;
        if (ffs &amp;lt; 16)&lt;br /&gt;
            return s - start;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* https://software.intel.com/sites/landingpage/IntrinsicsGuide/&lt;br /&gt;
* https://woboq.com/blog/utf-8-processing-using-simd.html&lt;br /&gt;
&lt;br /&gt;
[[Category:Programming]]&lt;br /&gt;
[[Category:C]]&lt;br /&gt;
[[Category:C++]]&lt;br /&gt;
[[Category:x86]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=MediaWiki:Copyright&amp;diff=338</id>
		<title>MediaWiki:Copyright</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=MediaWiki:Copyright&amp;diff=338"/>
		<updated>2022-11-13T20:15:30Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add a link to my mastodon profile&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;All pages &amp;amp;copy; Copyright 2019-2020 &amp;amp;mdash; &amp;lt;html&amp;gt;&amp;lt;a rel=&amp;quot;me&amp;quot; href=&amp;quot;https://mastodon.social/@vegard&amp;quot;&amp;gt;Vegard Nossum&amp;lt;/a&amp;gt;&amp;lt;/html&amp;gt;, unless otherwise noted.&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=337</id>
		<title>GLSL snippets</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=337"/>
		<updated>2022-10-24T22:56:27Z</updated>

		<summary type="html">&lt;p&gt;Vegard: /* Smooth variant */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Signed distance functions ==&lt;br /&gt;
&lt;br /&gt;
=== Antialiasing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float scale = 100.;&lt;br /&gt;
&lt;br /&gt;
void mainImage( out vec4 fragColor, in vec2 fragCoord )&lt;br /&gt;
{&lt;br /&gt;
    vec2 uv = scale * (fragCoord - .5 * iResolution.xy) / iResolution.y;&lt;br /&gt;
    float d = sd...(uv);&lt;br /&gt;
    vec3 col = vec3(1) * smoothstep(-0., 1.5 * scale / iResolution.y, d);&lt;br /&gt;
    fragColor = vec4(col, 1.);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The point here is to convert the length returned by the distance function into a number of pixels, and then we can smooth the outline over the precise number of pixels that we want (here 1.5).&lt;br /&gt;
&lt;br /&gt;
== Ray marching ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {&lt;br /&gt;
    vec2 xy = fragCoord - size / 2.;&lt;br /&gt;
    float z = size.y / tan(radians(fieldOfView) / 2.) / 2.;&lt;br /&gt;
    return normalize(vec3(xy, -z));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: The original &amp;lt;tt&amp;gt;rayDirection()&amp;lt;/tt&amp;gt; is missing the divide by 2 when calculating z. This causes the field of view parameter to be incorrect.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
float castRay(const int scene, vec3 eye, vec3 dir,&lt;br /&gt;
    float start, float end, float epsilon, int max_marching_steps,&lt;br /&gt;
    out int material)&lt;br /&gt;
{&lt;br /&gt;
    float depth = start;&lt;br /&gt;
    for (int i = 0; i &amp;lt; max_marching_steps; i++) {&lt;br /&gt;
        float d = sceneSDF(scene, eye + depth * dir, material);&lt;br /&gt;
        if (d &amp;lt; epsilon)&lt;br /&gt;
            return depth;&lt;br /&gt;
&lt;br /&gt;
        depth += d;&lt;br /&gt;
        if (depth &amp;gt;= end)&lt;br /&gt;
            break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return end;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm&lt;br /&gt;
vec3 estimateNormal( const int scene, const float epsilon, in vec3 p )&lt;br /&gt;
{&lt;br /&gt;
    int m;&lt;br /&gt;
    &lt;br /&gt;
    const vec2 k = vec2(1,-1);&lt;br /&gt;
    return normalize( k.xyy*sceneSDF( scene, p + k.xyy*epsilon, m ) + &lt;br /&gt;
                      k.yyx*sceneSDF( scene, p + k.yyx*epsilon, m ) + &lt;br /&gt;
                      k.yxy*sceneSDF( scene, p + k.yxy*epsilon, m ) + &lt;br /&gt;
                      k.xxx*sceneSDF( scene, p + k.xxx*epsilon, m ) );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Matrix transformations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml&lt;br /&gt;
mat4 rotate(float a, vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    float c = cos(a);&lt;br /&gt;
    vec3 ci = (1. - c) * v;&lt;br /&gt;
    vec3 s = sin(a) * v;&lt;br /&gt;
&lt;br /&gt;
    return mat4(&lt;br /&gt;
        ci.x * v.x + c, ci.x * v.y + s.z, ci.x * v.z - s.y, 0,&lt;br /&gt;
        ci.y * v.x - s.z, ci.y * v.y + c, ci.y * v.z + s.x, 0,&lt;br /&gt;
        ci.z * v.x + s.y, ci.z * v.y - s.x, ci.z * v.z + c, 0,&lt;br /&gt;
        0, 0, 0, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml&lt;br /&gt;
mat4 translate(vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    return mat4(&lt;br /&gt;
        1, 0, 0, 0,&lt;br /&gt;
        0, 1, 0, 0,&lt;br /&gt;
        0, 0, 1, 0,&lt;br /&gt;
        v.x, v.y, v.z, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Noise ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner&lt;br /&gt;
float rand(vec2 co)&lt;br /&gt;
{&lt;br /&gt;
    return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Colours ==&lt;br /&gt;
&lt;br /&gt;
=== HSV ===&lt;br /&gt;
&lt;br /&gt;
==== Plain HSV ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://github.com/hughsk/glsl-hsv2rgb/blob/master/index.glsl&lt;br /&gt;
vec3 hsv2rgb(vec3 c) {&lt;br /&gt;
    vec4 K = vec4(3. / 3., 2. / 3., 1. / 3., 3.);&lt;br /&gt;
    vec3 p = abs(fract(c.xxx + K.xyz) * 6. - K.www);&lt;br /&gt;
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Smooth variant ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb2.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb2()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.shadertoy.com/view/wlsSRB&lt;br /&gt;
vec3 hsv2rgb2(vec3 c, float k) {&lt;br /&gt;
    return smoothstep(0. + k, 1. - k,&lt;br /&gt;
                      .5 + .5 * cos((vec3(c.x) + vec3(3., 2., 1.) / 3.) * radians(360.)));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A good value for &amp;lt;code&amp;gt;k&amp;lt;/code&amp;gt; is e.g. 0.07.&lt;br /&gt;
&lt;br /&gt;
=== Gamma ===&lt;br /&gt;
&lt;br /&gt;
{{Main|Gamma}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float gamma = 2.2;&lt;br /&gt;
&lt;br /&gt;
// convert from sRGB to RGB&lt;br /&gt;
vec3 col = pow(col, vec3(gamma));&lt;br /&gt;
&lt;br /&gt;
// blending, etc.&lt;br /&gt;
&lt;br /&gt;
// gamma correction (RGB to sRGB)&lt;br /&gt;
col = pow(col, vec3(1. / gamma));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dithering ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
/* https://en.wikipedia.org/wiki/Ordered_dithering */&lt;br /&gt;
const float bayer_matrix[64] = float[64](&lt;br /&gt;
     -0.500000,  0.250000, -0.312500,  0.437500, -0.453125,  0.296875, -0.265625,  0.484375,&lt;br /&gt;
      0.000000, -0.250000,  0.187500, -0.062500,  0.046875, -0.203125,  0.234375, -0.015625,&lt;br /&gt;
     -0.375000,  0.375000, -0.437500,  0.312500, -0.328125,  0.421875, -0.390625,  0.359375,&lt;br /&gt;
      0.125000, -0.125000,  0.062500, -0.187500,  0.171875, -0.078125,  0.109375, -0.140625,&lt;br /&gt;
     -0.468750,  0.281250, -0.281250,  0.468750, -0.484375,  0.265625, -0.296875,  0.453125,&lt;br /&gt;
      0.031250, -0.218750,  0.218750, -0.031250,  0.015625, -0.234375,  0.203125, -0.046875,&lt;br /&gt;
     -0.343750,  0.406250, -0.406250,  0.343750, -0.359375,  0.390625, -0.421875,  0.328125,&lt;br /&gt;
      0.156250, -0.093750,  0.093750, -0.156250,  0.140625, -0.109375,  0.078125, -0.171875&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
float dither(vec2 uv, float levels, float sharpness, float intensity)&lt;br /&gt;
{&lt;br /&gt;
    int x = int(floor(uv.x)) &amp;amp; 7;&lt;br /&gt;
    int y = int(floor(uv.y)) &amp;amp; 7;&lt;br /&gt;
    float threshold = bayer_matrix[8 * y + x];&lt;br /&gt;
#if 0 // full dither&lt;br /&gt;
    return round(levels * intensity + threshold) / levels;&lt;br /&gt;
#else // respect sharpness&lt;br /&gt;
    float major = floor(levels * intensity);&lt;br /&gt;
    float minor = float(fract(levels * intensity) &amp;gt; .5 + sharpness * threshold);&lt;br /&gt;
    return (major + minor) / levels;&lt;br /&gt;
#endif&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Post-processing effects ==&lt;br /&gt;
&lt;br /&gt;
=== Volumetric light scattering (God rays) ===&lt;br /&gt;
&lt;br /&gt;
[[File:godrays.png|420px|thumb|Example of volumetric light scattering post-processing effect (with dithering).]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-13-volumetric-light-scattering-post-process&lt;br /&gt;
vec3 godrays(in vec2 ScreenLightPos, in vec2 fragCoord, out vec4 fragColor)&lt;br /&gt;
{&lt;br /&gt;
    const int NUM_SAMPLES = 16;&lt;br /&gt;
    const float Density = .7;&lt;br /&gt;
    const float Weight = .3;&lt;br /&gt;
    const float Decay = .88;&lt;br /&gt;
    const float Exposure = .4;&lt;br /&gt;
&lt;br /&gt;
    vec2 texCoord = fragCoord / iResolution.xy;&lt;br /&gt;
    vec2 deltaTexCoord = (texCoord - ScreenLightPos.xy);&lt;br /&gt;
    deltaTexCoord *= 1.0f / float(NUM_SAMPLES) * Density;&lt;br /&gt;
&lt;br /&gt;
    vec3 color = texture(iChannel0, texCoord).rgb;&lt;br /&gt;
    float illuminationDecay = 1.0f;&lt;br /&gt;
&lt;br /&gt;
    for (int i = 0; i &amp;lt; NUM_SAMPLES; i++) {&lt;br /&gt;
        texCoord -= deltaTexCoord;&lt;br /&gt;
&lt;br /&gt;
        float dither = rand(fragCoord + vec2(200. * float(i), 23. * float(i)));&lt;br /&gt;
        vec3 sample_ = texture(iChannel0, texCoord + deltaTexCoord * dither).rgb;&lt;br /&gt;
        sample_ *= illuminationDecay * Weight;&lt;br /&gt;
        color += sample_;&lt;br /&gt;
        illuminationDecay *= Decay;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return color * Exposure;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dithering suggested by Jessica Mak.&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=ftrace&amp;diff=336</id>
		<title>ftrace</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=ftrace&amp;diff=336"/>
		<updated>2022-10-07T14:37:04Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Trace a single system call ==&lt;br /&gt;
&lt;br /&gt;
This generates a function graph trace of a specific function and its callees:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Bash&amp;quot;&amp;gt;&lt;br /&gt;
# function to trace&lt;br /&gt;
func=ksys_mount&lt;br /&gt;
&lt;br /&gt;
cd /sys/kernel/debug/tracing/&lt;br /&gt;
echo 0 &amp;gt; tracing_on&lt;br /&gt;
echo function_graph &amp;gt; current_tracer&lt;br /&gt;
echo $func &amp;gt; set_graph_function&lt;br /&gt;
echo 1 &amp;gt; tracing_on&lt;br /&gt;
echo &amp;gt; trace&lt;br /&gt;
&lt;br /&gt;
# do thing here&lt;br /&gt;
&lt;br /&gt;
echo 0 &amp;gt; tracing_on&lt;br /&gt;
echo nop &amp;gt; current_tracer&lt;br /&gt;
&lt;br /&gt;
# save trace&lt;br /&gt;
cp trace /tmp/trace.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Linux kernel]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=mkinitrd&amp;diff=335</id>
		<title>mkinitrd</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=mkinitrd&amp;diff=335"/>
		<updated>2022-10-07T14:36:55Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add ftrace link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A handy way to run a program as init without a filesystem:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Bash&amp;quot;&amp;gt;&lt;br /&gt;
#! /bin/bash&lt;br /&gt;
&lt;br /&gt;
set -e&lt;br /&gt;
set -u&lt;br /&gt;
set -x&lt;br /&gt;
&lt;br /&gt;
rm -rf initrd/&lt;br /&gt;
mkdir initrd/&lt;br /&gt;
g++ -static [...] -o initrd/init main.cc&lt;br /&gt;
&lt;br /&gt;
(cd initrd/ &amp;amp;&amp;amp; (find | cpio -o -H newc)) \&lt;br /&gt;
        | gzip -c \&lt;br /&gt;
        &amp;gt; initrd.gz&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Mounting filesystems ===&lt;br /&gt;
&lt;br /&gt;
Sometimes it can be useful to have &amp;lt;tt&amp;gt;/proc&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/sys&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;/dev&amp;lt;/tt&amp;gt;, etc. around:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/mount.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/stat.h&amp;gt;&lt;br /&gt;
#include &amp;lt;sys/types.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;
#include &amp;lt;error.h&amp;gt;&lt;br /&gt;
#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
static void mkdirp(const char *name)&lt;br /&gt;
{&lt;br /&gt;
        if (mkdir(name, 0777) == -1 &amp;amp;&amp;amp; errno != EEXIST)&lt;br /&gt;
                error(EXIT_FAILURE, errno, &amp;quot;mkdir()&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        pid_t self = getpid();&lt;br /&gt;
        if (getpid() == -1)&lt;br /&gt;
                error(EXIT_FAILURE, errno, &amp;quot;getpid()&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (self == 1) {&lt;br /&gt;
                // We&#039;re init! Do some basic setup.&lt;br /&gt;
&lt;br /&gt;
                mkdirp(&amp;quot;/proc&amp;quot;);&lt;br /&gt;
                if (mount(&amp;quot;nodev&amp;quot;, &amp;quot;/proc&amp;quot;, &amp;quot;proc&amp;quot;, 0, &amp;quot;&amp;quot;) == -1)&lt;br /&gt;
                        error(EXIT_FAILURE, errno, &amp;quot;mount(/proc)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                mkdirp(&amp;quot;/sys&amp;quot;);&lt;br /&gt;
                if (mount(&amp;quot;nodev&amp;quot;, &amp;quot;/sys&amp;quot;, &amp;quot;sysfs&amp;quot;, 0, &amp;quot;&amp;quot;) == -1)&lt;br /&gt;
                        error(EXIT_FAILURE, errno, &amp;quot;mount(/sys)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                mkdirp(&amp;quot;/dev&amp;quot;);&lt;br /&gt;
                if (mount(&amp;quot;nodev&amp;quot;, &amp;quot;/dev&amp;quot;, &amp;quot;devtmpfs&amp;quot;, 0, &amp;quot;&amp;quot;) == -1)&lt;br /&gt;
                        error(EXIT_FAILURE, errno, &amp;quot;mount(/dev)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
                if (mount(&amp;quot;nodev&amp;quot;, &amp;quot;/sys/kernel/tracing&amp;quot;, &amp;quot;tracefs&amp;quot;, 0, &amp;quot;&amp;quot;) == -1)&lt;br /&gt;
                        error(EXIT_FAILURE, errno, &amp;quot;mount(/sys/kernel/tracing)&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== ftrace ===&lt;br /&gt;
&lt;br /&gt;
To trace something with ftrace (and dump the trace), use something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#define tracing_set(name, value) \&lt;br /&gt;
        { \&lt;br /&gt;
                FILE *fp = fopen(&amp;quot;/sys/kernel/tracing/&amp;quot; #name, &amp;quot;w&amp;quot;); \&lt;br /&gt;
                if (!fp) \&lt;br /&gt;
                        error(EXIT_FAILURE, errno, &amp;quot;fopen(&amp;quot; #name &amp;quot;)&amp;quot;); \&lt;br /&gt;
                fprintf(fp, &amp;quot;%s\n&amp;quot;, #value); \&lt;br /&gt;
                fclose(fp); \&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        // ...&lt;br /&gt;
&lt;br /&gt;
        tracing_set(current_tracer, function_graph);&lt;br /&gt;
        tracing_set(tracing_on, 1);&lt;br /&gt;
&lt;br /&gt;
        // insert traced code here&lt;br /&gt;
&lt;br /&gt;
        tracing_set(tracing_on, 0);&lt;br /&gt;
&lt;br /&gt;
        // dump trace&lt;br /&gt;
        {&lt;br /&gt;
                FILE *fp = fopen(&amp;quot;/sys/kernel/tracing/trace&amp;quot;, &amp;quot;r&amp;quot;);&lt;br /&gt;
                while (fp &amp;amp;&amp;amp; !feof(fp)) {&lt;br /&gt;
                        char buf[1024];&lt;br /&gt;
                        size_t len = fread(buf, 1, sizeof buf, fp);&lt;br /&gt;
                        fwrite(buf, 1, len, stdout);&lt;br /&gt;
                }&lt;br /&gt;
                fclose(fp);&lt;br /&gt;
        }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See also: [[ftrace]].&lt;br /&gt;
&lt;br /&gt;
[[Category:Linux kernel]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=ftrace&amp;diff=334</id>
		<title>ftrace</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=ftrace&amp;diff=334"/>
		<updated>2022-10-07T14:14:15Z</updated>

		<summary type="html">&lt;p&gt;Vegard: fixes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Trace a single system call ==&lt;br /&gt;
&lt;br /&gt;
This generates a function graph trace of a specific function and its callees:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Bash&amp;quot;&amp;gt;&lt;br /&gt;
# function to trace&lt;br /&gt;
func=ksys_mount&lt;br /&gt;
&lt;br /&gt;
cd /sys/kernel/debug/tracing/&lt;br /&gt;
echo 0 &amp;gt; tracing_on&lt;br /&gt;
echo function_graph &amp;gt; current_tracer&lt;br /&gt;
echo $func &amp;gt; set_graph_function&lt;br /&gt;
echo 1 &amp;gt; tracing_on&lt;br /&gt;
echo &amp;gt; trace&lt;br /&gt;
&lt;br /&gt;
# do thing here&lt;br /&gt;
&lt;br /&gt;
echo 0 &amp;gt; tracing_on&lt;br /&gt;
echo nop &amp;gt; current_tracer&lt;br /&gt;
&lt;br /&gt;
# save trace&lt;br /&gt;
cp trace /tmp/trace.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=ftrace&amp;diff=333</id>
		<title>ftrace</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=ftrace&amp;diff=333"/>
		<updated>2022-10-07T14:09:46Z</updated>

		<summary type="html">&lt;p&gt;Vegard: fix&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Trace a single system call ==&lt;br /&gt;
&lt;br /&gt;
This generates a function graph trace of a specific function and its callees:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Bash&amp;quot;&amp;gt;&lt;br /&gt;
# function to trace&lt;br /&gt;
func=ksys_mount&lt;br /&gt;
&lt;br /&gt;
cd /sys/kernel/debug/tracing/&lt;br /&gt;
echo 0 &amp;gt; tracing_on&lt;br /&gt;
echo function_graph &amp;gt; current_tracer&lt;br /&gt;
echo $func &amp;gt; set_graph_function&lt;br /&gt;
echo 1 &amp;gt; tracing_on&lt;br /&gt;
&lt;br /&gt;
# do thing here&lt;br /&gt;
&lt;br /&gt;
echo 0 &amp;gt; tracing_on&lt;br /&gt;
&lt;br /&gt;
# save trace&lt;br /&gt;
cp trace /tmp/trace.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=ftrace&amp;diff=332</id>
		<title>ftrace</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=ftrace&amp;diff=332"/>
		<updated>2022-10-07T14:08:34Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Trace a single system call ==&lt;br /&gt;
&lt;br /&gt;
This generates a function graph trace of a specific function and its callees:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;Bash&amp;quot;&amp;gt;&lt;br /&gt;
# function to trace&lt;br /&gt;
func=ksys_mount&lt;br /&gt;
&lt;br /&gt;
cd /sys/kernel/debug/tracing/&lt;br /&gt;
echo 0 &amp;gt; tracing_on&lt;br /&gt;
echo function_graph &amp;gt; current_tracer&lt;br /&gt;
echo set_graph_function &amp;gt; set_graph_function&lt;br /&gt;
echo $func &amp;gt; set_graph_function&lt;br /&gt;
echo 1 &amp;gt; tracing_on&lt;br /&gt;
&lt;br /&gt;
# do thing here&lt;br /&gt;
&lt;br /&gt;
echo 0 &amp;gt; tracing_on&lt;br /&gt;
&lt;br /&gt;
# save trace&lt;br /&gt;
cp trace /tmp/trace.txt&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Frame_analysis&amp;diff=331</id>
		<title>Frame analysis</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Frame_analysis&amp;diff=331"/>
		<updated>2022-01-20T06:53:53Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add God of War&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a list of &amp;quot;frame analysis&amp;quot; blog posts, i.e. posts which dissect how a game does its rendering.&lt;br /&gt;
&lt;br /&gt;
== Engines ==&lt;br /&gt;
&lt;br /&gt;
=== AnKi 3D ===&lt;br /&gt;
&lt;br /&gt;
* http://anki3d.org/anatomy-of-a-frame-in-anki/&lt;br /&gt;
&lt;br /&gt;
== Games ==&lt;br /&gt;
&lt;br /&gt;
=== A Plague Tale: Innocence ===&lt;br /&gt;
&lt;br /&gt;
* https://gamingbolt.com/a-plague-tale-innocence-graphics-analysis-one-of-the-best-looking-games-of-this-gen&lt;br /&gt;
&lt;br /&gt;
=== Batman: Arkham Knight ===&lt;br /&gt;
&lt;br /&gt;
* http://morad.in/2020/04/03/unmasking-arkham-knight/&lt;br /&gt;
&lt;br /&gt;
=== Battlefield 3 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.slideshare.net/DICEStudio/directx-11-rendering-in-battlefield-3&lt;br /&gt;
&lt;br /&gt;
=== Battlefield 4 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.slideshare.net/DevCentralAMD/rendering-battlefield-4-with-mantle-yuriy-o-donnell&lt;br /&gt;
&lt;br /&gt;
=== BioShock Infinite ===&lt;br /&gt;
&lt;br /&gt;
* https://solid-angle.blogspot.com/2014/03/bioshock-infinite-lighting.html&lt;br /&gt;
&lt;br /&gt;
=== Castlevania: Lords of Shadow 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.elopezr.com/castlevania-lords-of-shadow-2-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Deus Ex: Human Revolution ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/03/10/deus-ex-human-revolution-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Doom 2016 ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2016/09/09/doom-2016-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Doom Eternal ===&lt;br /&gt;
* https://simoncoenen.com/blog/programming/graphics/DoomEternalStudy.html&lt;br /&gt;
&lt;br /&gt;
=== Far Cry 5 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.gdcvault.com/play/1025480/Terrain-Rendering-in-Far-Cry&lt;br /&gt;
&lt;br /&gt;
=== Gears of War 5 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.eurogamer.net/articles/digitalfoundry-2019-gears-5-tech-interview&lt;br /&gt;
&lt;br /&gt;
=== Ghost of Tsushima ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.selfshadow.com/publications/s2020-shading-course/patry/slides/&lt;br /&gt;
&lt;br /&gt;
=== God of War ===&lt;br /&gt;
&lt;br /&gt;
* http://www.mamoniem.com/behind-the-pretty-frames-god-of-war/&lt;br /&gt;
&lt;br /&gt;
=== GTA V ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Killzone 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.guerrilla-games.com/read/deferred-rendering-in-killzone-2&lt;br /&gt;
&lt;br /&gt;
=== League of Legends ===&lt;br /&gt;
&lt;br /&gt;
* https://technology.riotgames.com/news/trip-down-lol-graphics-pipeline&lt;br /&gt;
&lt;br /&gt;
=== Metal Gear Solid V ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2017/12/15/mgs-v-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Metro Exodus ===&lt;br /&gt;
&lt;br /&gt;
* https://aschrein.github.io/2019/08/11/metro_breakdown.html&lt;br /&gt;
&lt;br /&gt;
=== Middle Earth: Shadow of Mordor ===&lt;br /&gt;
&lt;br /&gt;
* http://www.elopezr.com/the-rendering-of-middle-earth-shadow-of-mordor/&lt;br /&gt;
&lt;br /&gt;
=== Ni No Kuni 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.thomaspoulet.fr/ninokuni2-frame/&lt;br /&gt;
&lt;br /&gt;
=== Red Dead Redemption 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://imgeself.github.io/posts/2020-06-19-graphics-study-rdr2/&lt;br /&gt;
&lt;br /&gt;
=== Resident Evil 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://aschrein.github.io/2019/08/01/re2_breakdown.html&lt;br /&gt;
&lt;br /&gt;
=== Rise of the Tomb Raider ===&lt;br /&gt;
&lt;br /&gt;
* http://www.elopezr.com/the-rendering-of-rise-of-the-tomb-raider/&lt;br /&gt;
&lt;br /&gt;
=== Supreme Commander ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/06/23/supreme-commander-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== The Witcher 3 ===&lt;br /&gt;
&lt;br /&gt;
* https://astralcode.blogspot.com/2018/11/reverse-engineering-rendering-of.html&lt;br /&gt;
&lt;br /&gt;
=== The Witness ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.thomaspoulet.fr/the-witness-frame-part-1/&lt;br /&gt;
* https://blog.thomaspoulet.fr/the-witness-frame-part-2/&lt;br /&gt;
&lt;br /&gt;
=== Total War ===&lt;br /&gt;
&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-2/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-3/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-4/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-5/&lt;br /&gt;
&lt;br /&gt;
=== Wind Waker ===&lt;br /&gt;
&lt;br /&gt;
* https://polycount.com/discussion/104415/zelda-wind-waker-tech-and-texture-analysis-picture-heavy&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=330</id>
		<title>GLSL snippets</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=GLSL_snippets&amp;diff=330"/>
		<updated>2021-12-30T11:02:01Z</updated>

		<summary type="html">&lt;p&gt;Vegard: /* Ray marching */ fix rayDirection()&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
== Signed distance functions ==&lt;br /&gt;
&lt;br /&gt;
=== Antialiasing ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float scale = 100.;&lt;br /&gt;
&lt;br /&gt;
void mainImage( out vec4 fragColor, in vec2 fragCoord )&lt;br /&gt;
{&lt;br /&gt;
    vec2 uv = scale * (fragCoord - .5 * iResolution.xy) / iResolution.y;&lt;br /&gt;
    float d = sd...(uv);&lt;br /&gt;
    vec3 col = vec3(1) * smoothstep(-0., 1.5 * scale / iResolution.y, d);&lt;br /&gt;
    fragColor = vec4(col, 1.);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The point here is to convert the length returned by the distance function into a number of pixels, and then we can smooth the outline over the precise number of pixels that we want (here 1.5).&lt;br /&gt;
&lt;br /&gt;
== Ray marching ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
vec3 rayDirection(float fieldOfView, vec2 size, vec2 fragCoord) {&lt;br /&gt;
    vec2 xy = fragCoord - size / 2.;&lt;br /&gt;
    float z = size.y / tan(radians(fieldOfView) / 2.) / 2.;&lt;br /&gt;
    return normalize(vec3(xy, -z));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: The original &amp;lt;tt&amp;gt;rayDirection()&amp;lt;/tt&amp;gt; is missing the divide by 2 when calculating z. This causes the field of view parameter to be incorrect.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://jamie-wong.com/2016/07/15/ray-marching-signed-distance-functions/&lt;br /&gt;
float castRay(const int scene, vec3 eye, vec3 dir,&lt;br /&gt;
    float start, float end, float epsilon, int max_marching_steps,&lt;br /&gt;
    out int material)&lt;br /&gt;
{&lt;br /&gt;
    float depth = start;&lt;br /&gt;
    for (int i = 0; i &amp;lt; max_marching_steps; i++) {&lt;br /&gt;
        float d = sceneSDF(scene, eye + depth * dir, material);&lt;br /&gt;
        if (d &amp;lt; epsilon)&lt;br /&gt;
            return depth;&lt;br /&gt;
&lt;br /&gt;
        depth += d;&lt;br /&gt;
        if (depth &amp;gt;= end)&lt;br /&gt;
            break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return end;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm&lt;br /&gt;
vec3 estimateNormal( const int scene, const float epsilon, in vec3 p )&lt;br /&gt;
{&lt;br /&gt;
    int m;&lt;br /&gt;
    &lt;br /&gt;
    const vec2 k = vec2(1,-1);&lt;br /&gt;
    return normalize( k.xyy*sceneSDF( scene, p + k.xyy*epsilon, m ) + &lt;br /&gt;
                      k.yyx*sceneSDF( scene, p + k.yyx*epsilon, m ) + &lt;br /&gt;
                      k.yxy*sceneSDF( scene, p + k.yxy*epsilon, m ) + &lt;br /&gt;
                      k.xxx*sceneSDF( scene, p + k.xxx*epsilon, m ) );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Matrix transformations ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glRotate.xml&lt;br /&gt;
mat4 rotate(float a, vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    float c = cos(a);&lt;br /&gt;
    vec3 ci = (1. - c) * v;&lt;br /&gt;
    vec3 s = sin(a) * v;&lt;br /&gt;
&lt;br /&gt;
    return mat4(&lt;br /&gt;
        ci.x * v.x + c, ci.x * v.y + s.z, ci.x * v.z - s.y, 0,&lt;br /&gt;
        ci.y * v.x - s.z, ci.y * v.y + c, ci.y * v.z + s.x, 0,&lt;br /&gt;
        ci.z * v.x + s.y, ci.z * v.y - s.x, ci.z * v.z + c, 0,&lt;br /&gt;
        0, 0, 0, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glTranslate.xml&lt;br /&gt;
mat4 translate(vec3 v)&lt;br /&gt;
{&lt;br /&gt;
    return mat4(&lt;br /&gt;
        1, 0, 0, 0,&lt;br /&gt;
        0, 1, 0, 0,&lt;br /&gt;
        0, 0, 1, 0,&lt;br /&gt;
        v.x, v.y, v.z, 1&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Noise ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner&lt;br /&gt;
float rand(vec2 co)&lt;br /&gt;
{&lt;br /&gt;
    return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Colours ==&lt;br /&gt;
&lt;br /&gt;
=== HSV ===&lt;br /&gt;
&lt;br /&gt;
==== Plain HSV ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://github.com/hughsk/glsl-hsv2rgb/blob/master/index.glsl&lt;br /&gt;
vec3 hsv2rgb(vec3 c) {&lt;br /&gt;
    vec4 K = vec4(3. / 3., 2. / 3., 1. / 3., 3.);&lt;br /&gt;
    vec3 p = abs(fract(c.xxx + K.xyz) * 6. - K.www);&lt;br /&gt;
    return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Smooth variant ====&lt;br /&gt;
&lt;br /&gt;
[[File:hsv2rgb2.png|420px|thumb|&amp;lt;tt&amp;gt;hsv2rgb2()&amp;lt;/tt&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://www.shadertoy.com/view/wlsSRB&lt;br /&gt;
vec3 hsv2rgb2(vec3 c, float k) {&lt;br /&gt;
    return smoothstep(0. + k, 1. - k,&lt;br /&gt;
                      .5 + .5 * cos((vec3(c.x) + vec3(3., 2., 1.) / 3.) * radians(360.)));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Gamma ===&lt;br /&gt;
&lt;br /&gt;
{{Main|Gamma}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float gamma = 2.2;&lt;br /&gt;
&lt;br /&gt;
// convert from sRGB to RGB&lt;br /&gt;
vec3 col = pow(col, vec3(gamma));&lt;br /&gt;
&lt;br /&gt;
// blending, etc.&lt;br /&gt;
&lt;br /&gt;
// gamma correction (RGB to sRGB)&lt;br /&gt;
col = pow(col, vec3(1. / gamma));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Dithering ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
/* https://en.wikipedia.org/wiki/Ordered_dithering */&lt;br /&gt;
const float bayer_matrix[64] = float[64](&lt;br /&gt;
     -0.500000,  0.250000, -0.312500,  0.437500, -0.453125,  0.296875, -0.265625,  0.484375,&lt;br /&gt;
      0.000000, -0.250000,  0.187500, -0.062500,  0.046875, -0.203125,  0.234375, -0.015625,&lt;br /&gt;
     -0.375000,  0.375000, -0.437500,  0.312500, -0.328125,  0.421875, -0.390625,  0.359375,&lt;br /&gt;
      0.125000, -0.125000,  0.062500, -0.187500,  0.171875, -0.078125,  0.109375, -0.140625,&lt;br /&gt;
     -0.468750,  0.281250, -0.281250,  0.468750, -0.484375,  0.265625, -0.296875,  0.453125,&lt;br /&gt;
      0.031250, -0.218750,  0.218750, -0.031250,  0.015625, -0.234375,  0.203125, -0.046875,&lt;br /&gt;
     -0.343750,  0.406250, -0.406250,  0.343750, -0.359375,  0.390625, -0.421875,  0.328125,&lt;br /&gt;
      0.156250, -0.093750,  0.093750, -0.156250,  0.140625, -0.109375,  0.078125, -0.171875&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
float dither(vec2 uv, float levels, float sharpness, float intensity)&lt;br /&gt;
{&lt;br /&gt;
    int x = int(floor(uv.x)) &amp;amp; 7;&lt;br /&gt;
    int y = int(floor(uv.y)) &amp;amp; 7;&lt;br /&gt;
    float threshold = bayer_matrix[8 * y + x];&lt;br /&gt;
#if 0 // full dither&lt;br /&gt;
    return round(levels * intensity + threshold) / levels;&lt;br /&gt;
#else // respect sharpness&lt;br /&gt;
    float major = floor(levels * intensity);&lt;br /&gt;
    float minor = float(fract(levels * intensity) &amp;gt; .5 + sharpness * threshold);&lt;br /&gt;
    return (major + minor) / levels;&lt;br /&gt;
#endif&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Post-processing effects ==&lt;br /&gt;
&lt;br /&gt;
=== Volumetric light scattering (God rays) ===&lt;br /&gt;
&lt;br /&gt;
[[File:godrays.png|420px|thumb|Example of volumetric light scattering post-processing effect (with dithering).]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
// https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-13-volumetric-light-scattering-post-process&lt;br /&gt;
vec3 godrays(in vec2 ScreenLightPos, in vec2 fragCoord, out vec4 fragColor)&lt;br /&gt;
{&lt;br /&gt;
    const int NUM_SAMPLES = 16;&lt;br /&gt;
    const float Density = .7;&lt;br /&gt;
    const float Weight = .3;&lt;br /&gt;
    const float Decay = .88;&lt;br /&gt;
    const float Exposure = .4;&lt;br /&gt;
&lt;br /&gt;
    vec2 texCoord = fragCoord / iResolution.xy;&lt;br /&gt;
    vec2 deltaTexCoord = (texCoord - ScreenLightPos.xy);&lt;br /&gt;
    deltaTexCoord *= 1.0f / float(NUM_SAMPLES) * Density;&lt;br /&gt;
&lt;br /&gt;
    vec3 color = texture(iChannel0, texCoord).rgb;&lt;br /&gt;
    float illuminationDecay = 1.0f;&lt;br /&gt;
&lt;br /&gt;
    for (int i = 0; i &amp;lt; NUM_SAMPLES; i++) {&lt;br /&gt;
        texCoord -= deltaTexCoord;&lt;br /&gt;
&lt;br /&gt;
        float dither = rand(fragCoord + vec2(200. * float(i), 23. * float(i)));&lt;br /&gt;
        vec3 sample_ = texture(iChannel0, texCoord + deltaTexCoord * dither).rgb;&lt;br /&gt;
        sample_ *= illuminationDecay * Weight;&lt;br /&gt;
        color += sample_;&lt;br /&gt;
        illuminationDecay *= Decay;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return color * Exposure;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dithering suggested by Jessica Mak.&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Blur_filter&amp;diff=329</id>
		<title>Blur filter</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Blur_filter&amp;diff=329"/>
		<updated>2021-12-28T12:42:31Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Best practices:&lt;br /&gt;
&lt;br /&gt;
* Scale down before applying filter to increase blur radius&lt;br /&gt;
* Separate into horizontal + vertical passes to reduce number of texture lookups&lt;br /&gt;
* Use hardware filtering to reduce number of texture lookups&lt;br /&gt;
* Make sure blending happens in [[Gamma|linear RGB]] to avoid darkening&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* https://www.codeproject.com/Articles/839187/An-investigation-of-fast-real-time-GPU-based-image&lt;br /&gt;
* https://iquilezles.org/www/articles/gamma/gamma.htm&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Gamma&amp;diff=328</id>
		<title>Gamma</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Gamma&amp;diff=328"/>
		<updated>2021-12-28T10:21:17Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quick rules of thumb, since I can never remember which is which:&lt;br /&gt;
* RGB = linear space&lt;br /&gt;
* sRGB = gamma space&lt;br /&gt;
* most image files store sRGB&lt;br /&gt;
* sRGB is unfit for blending, blurring, etc.&lt;br /&gt;
&lt;br /&gt;
The corollary is:&lt;br /&gt;
* Image files loaded as textures should be converted from sRGB to RGB (but some decoders do this for you!)&lt;br /&gt;
* Since alpha is linear, [[Premultiplied alpha|alpha premultiplication]] should happen in linear space, i.e. after converting to RGB [http://ssp.impulsetrain.com/gamma-premult.html]&lt;br /&gt;
* The shader responsible for putting the final pixels on the screen should have a gamma correction step doing:&lt;br /&gt;
:&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float gamma = 2.2;&lt;br /&gt;
&lt;br /&gt;
out vec4 color;&lt;br /&gt;
&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    color = pow(color, 1. / gamma);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note, however, that OpenGL may also perform this step for you on any on-screen framebuffers (i.e. the default framebuffer) if you do &amp;lt;code&amp;gt;glEnable(GL_FRAMEBUFFER_SRGB)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* https://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-about-gamma/&lt;br /&gt;
* https://stackoverflow.com/questions/23026151/do-i-need-to-gamma-correct-the-final-color-output-on-a-modern-computer-monitor&lt;br /&gt;
* https://www.khronos.org/opengl/wiki/Framebuffer#Colorspace&lt;br /&gt;
* https://en.wikipedia.org/wiki/Gamma_correction&lt;br /&gt;
* https://www.cambridgeincolour.com/tutorials/gamma-correction.htm&lt;br /&gt;
* http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html&lt;br /&gt;
* https://unlimited3d.wordpress.com/2020/01/08/srgb-color-space-in-opengl/&lt;br /&gt;
* https://mynameismjp.wordpress.com/2012/10/24/msaa-overview/ (&amp;quot;Working with HDR and Tone Mapping&amp;quot;)&lt;br /&gt;
* https://iquilezles.org/www/articles/gamma/gamma.htm&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Tone_mapping&amp;diff=327</id>
		<title>Tone mapping</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Tone_mapping&amp;diff=327"/>
		<updated>2021-12-26T14:27:18Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
== See also == &lt;br /&gt;
* https://learnopengl.com/Advanced-Lighting/HDR&lt;br /&gt;
* http://filmicworlds.com/blog/filmic-tonemapping-operators/&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Point-triangle_intersection&amp;diff=326</id>
		<title>Point-triangle intersection</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Point-triangle_intersection&amp;diff=326"/>
		<updated>2021-12-09T13:01:28Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
=== See also ===&lt;br /&gt;
&lt;br /&gt;
* https://twitter.com/SebAaltonen/status/1468674844510330882&lt;br /&gt;
* [[Barycentric coordinates]]&lt;br /&gt;
* [[Ray-triangle intersection]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Ray-triangle_intersection&amp;diff=325</id>
		<title>Ray-triangle intersection</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Ray-triangle_intersection&amp;diff=325"/>
		<updated>2021-12-08T08:13:59Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;source lang=&amp;quot;C++&amp;quot;&amp;gt;&lt;br /&gt;
// https://twitter.com/brunolevy01/status/1229664999179726848&lt;br /&gt;
// &amp;quot;(Moller-Tumblore). A, B, C is the triangle, O, D is the ray.&amp;quot;&lt;br /&gt;
// gives barycentric coordinates and normal for free.&lt;br /&gt;
bool ray_triangle_intersection(vec3 A, vec3 B, vec3 C, vec3 O, vec3 D)&lt;br /&gt;
{&lt;br /&gt;
    vec3 E1 = B - A;&lt;br /&gt;
    vec3 E2 = C - A;&lt;br /&gt;
    vec3 N = cross(E1, E2);&lt;br /&gt;
    float det = -dot(D, N);&lt;br /&gt;
    vec3 AO = O - A;&lt;br /&gt;
    vec3 DAO = cross(AO, D);&lt;br /&gt;
    float u =  dot(E2, DAO) / det;&lt;br /&gt;
    float v = -dot(E1, DAO) / det;&lt;br /&gt;
    float t =  dot(AO, N) / det;&lt;br /&gt;
    return (t &amp;gt; 0. &amp;amp;&amp;amp; u &amp;gt; 0. &amp;amp;&amp;amp; v &amp;gt; 0. &amp;amp;&amp;amp; (u + v) &amp;lt; 1.);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== See also ===&lt;br /&gt;
&lt;br /&gt;
* [[Barycentric coordinates]]&lt;br /&gt;
* https://twitter.com/BrunoLevy01/status/1229665598273150979&lt;br /&gt;
* https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d/42752998#42752998&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;br /&gt;
[[Category:Geometry]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Ray-triangle_intersection&amp;diff=324</id>
		<title>Ray-triangle intersection</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Ray-triangle_intersection&amp;diff=324"/>
		<updated>2021-12-08T08:13:36Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;source lang=&amp;quot;C++&amp;quot;&amp;gt;&lt;br /&gt;
// https://twitter.com/brunolevy01/status/1229664999179726848&lt;br /&gt;
// &amp;quot;(Moller-Tumblore). A, B, C is the triangle, O, D is the ray.&amp;quot;&lt;br /&gt;
// gives barycentric coordinates and normal for free.&lt;br /&gt;
bool ray_triangle_intersection(vec3 A, vec3 B, vec3 C, vec3 O, vec3 D)&lt;br /&gt;
{&lt;br /&gt;
    vec3 E1 = B - A;&lt;br /&gt;
    vec3 E2 = C - A;&lt;br /&gt;
    vec3 N = cross(E1, E2);&lt;br /&gt;
    float det = -dot(D, N);&lt;br /&gt;
    vec3 AO = O - A;&lt;br /&gt;
    vec3 DAO = cross(AO, D);&lt;br /&gt;
    float u =  dot(E2, DAO) / det;&lt;br /&gt;
    float v = -dot(E1, DAO) / det;&lt;br /&gt;
    float t =  dot(AO, N) / det;&lt;br /&gt;
    return (t &amp;gt; 0. &amp;amp;&amp;amp; u &amp;gt; 0. &amp;amp;&amp;amp; v &amp;gt; 0. &amp;amp;&amp;amp; (u + v) &amp;lt; 1.);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== See also ===&lt;br /&gt;
&lt;br /&gt;
* [[Barycentric coordinates]]&lt;br /&gt;
* https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d/42752998#42752998&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;br /&gt;
[[Category:Geometry]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Nanite&amp;diff=323</id>
		<title>Nanite</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Nanite&amp;diff=323"/>
		<updated>2021-06-15T06:55:27Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [https://www.unrealengine.com/en-US/blog/understanding-nanite---unreal-engine-5-s-new-virtualized-geometry-system &amp;quot;Understanding Nanite - Unreal Engine 5&#039;s new virtualized geometry system&amp;quot;]&lt;br /&gt;
* [https://docs.unrealengine.com/5.0/en-US/RenderingFeatures/Nanite/ &amp;quot;Nanite Virtualized Geometry&amp;quot;]&lt;br /&gt;
* [http://www.elopezr.com/a-macro-view-of-nanite/ &amp;quot;A macro view of Nanite&amp;quot;]&lt;br /&gt;
* [https://www.ezdlc.com/128181/nanite-presentation-how-it-works/ &amp;quot;Nanite presentation: How it works&amp;quot;]&lt;br /&gt;
* [https://www.notion.so/Brief-Analysis-of-Nanite-94be60f292434ba3ae62fa4bcf7d9379 &amp;quot;Brief Analysis of Nanite&amp;quot;]&lt;br /&gt;
* [https://www.notion.so/Brief-Analysis-of-Nanite-GPU-Culling-6ea4a7b8a3574f31bb4095901fc8e309 &amp;quot;Brief Analysis of Nanite GPU Culling&amp;quot;]&lt;br /&gt;
* https://zhuanlan.zhihu.com/p/376786001&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Nanite&amp;diff=322</id>
		<title>Nanite</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Nanite&amp;diff=322"/>
		<updated>2021-06-08T13:36:35Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new article&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* [https://www.unrealengine.com/en-US/blog/understanding-nanite---unreal-engine-5-s-new-virtualized-geometry-system &amp;quot;Understanding Nanite - Unreal Engine 5&#039;s new virtualized geometry system&amp;quot;]&lt;br /&gt;
* [https://docs.unrealengine.com/5.0/en-US/RenderingFeatures/Nanite/ &amp;quot;Nanite Virtualized Geometry&amp;quot;]&lt;br /&gt;
* [http://www.elopezr.com/a-macro-view-of-nanite/ &amp;quot;A macro view of Nanite&amp;quot;]&lt;br /&gt;
* [https://www.ezdlc.com/128181/nanite-presentation-how-it-works/ &amp;quot;Nanite presentation: How it works&amp;quot;]&lt;br /&gt;
* [https://www.notion.so/Brief-Analysis-of-Nanite-94be60f292434ba3ae62fa4bcf7d9379 &amp;quot;Brief Analysis of Nanite&amp;quot;]&lt;br /&gt;
* https://zhuanlan.zhihu.com/p/376786001&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Category:Floating-point&amp;diff=321</id>
		<title>Category:Floating-point</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Category:Floating-point&amp;diff=321"/>
		<updated>2021-06-08T05:57:24Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Herbie&amp;diff=320</id>
		<title>Herbie</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Herbie&amp;diff=320"/>
		<updated>2021-06-08T05:57:12Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;quot;Herbie rewrites floating point expressions to make them more accurate. Floating point arithmetic is inaccurate; even 0.1 + 0.2 ≠ 0.3 for a computer. Herbie helps find and fix these mysterious inaccuracies.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
http://herbie.uwplse.org/&lt;br /&gt;
&lt;br /&gt;
[[Category:Floating-point]]&lt;br /&gt;
[[Category:Programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Float_to_byte_quantisation&amp;diff=319</id>
		<title>Float to byte quantisation</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Float_to_byte_quantisation&amp;diff=319"/>
		<updated>2021-06-08T05:52:56Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
[[File:quantization.png]]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* https://stackoverflow.com/questions/1914115/converting-color-value-from-float-0-1-to-byte-0-255&lt;br /&gt;
* https://twitter.com/rygorous/status/1249876256599846912&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;br /&gt;
[[Category:Floating-point]]&lt;br /&gt;
[[Category:Programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Bit-twiddling_hacks&amp;diff=318</id>
		<title>Bit-twiddling hacks</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Bit-twiddling_hacks&amp;diff=318"/>
		<updated>2021-04-19T11:01:24Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== See also ==&lt;br /&gt;
&lt;br /&gt;
* https://graphics.stanford.edu/~seander/bithacks.html&lt;br /&gt;
* http://www.csl.sri.com/users/tiwari/papers/pldi2011-bitvector.pdf&lt;br /&gt;
&lt;br /&gt;
[[Category:C]] [[Category:Assembly]] [[Category:Programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Buffer_iteration&amp;diff=317</id>
		<title>Buffer iteration</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Buffer_iteration&amp;diff=317"/>
		<updated>2021-02-26T09:06:48Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
In order:&lt;br /&gt;
* https://fgiesen.wordpress.com/2011/11/21/buffer-centric-io/&lt;br /&gt;
* https://twitter.com/pervognsen/status/1260381122887737344&lt;br /&gt;
* https://gist.github.com/pervognsen/744066869da509a15c4e08fc9408207e&lt;br /&gt;
* https://gist.github.com/vurtun/192cac1f1818417d7b4067d60e4fe921&lt;br /&gt;
* https://gist.github.com/pervognsen/d57cdc165e79a21637fe5a721375afba&lt;br /&gt;
&lt;br /&gt;
[[Category:C]] [[Category:Programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Random_number_generators&amp;diff=316</id>
		<title>Random number generators</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Random_number_generators&amp;diff=316"/>
		<updated>2021-02-20T15:36:33Z</updated>

		<summary type="html">&lt;p&gt;Vegard: categorise&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== pcg32() ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
// https://twitter.com/zeuxcg/status/1363143368033755136&lt;br /&gt;
uint32_t pcg32(uint64_t* s) {&lt;br /&gt;
  uint32_t x = ((*s &amp;gt;&amp;gt; 18u) ^ *s) &amp;gt;&amp;gt; 27u;&lt;br /&gt;
  uint32_t r = *s &amp;gt;&amp;gt; 59u;&lt;br /&gt;
  *s  = *s * 6364136223846793005ULL + 1;&lt;br /&gt;
  return (x &amp;gt;&amp;gt; r) | (x &amp;lt;&amp;lt; ((-r) &amp;amp; 31));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* PCG paper: https://www.pcg-random.org/pdf/hmc-cs-2014-0905.pdf&lt;br /&gt;
&lt;br /&gt;
[[Category:C]] [[Category:Programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Random_number_generators&amp;diff=315</id>
		<title>Random number generators</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Random_number_generators&amp;diff=315"/>
		<updated>2021-02-20T15:35:35Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== pcg32() ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
// https://twitter.com/zeuxcg/status/1363143368033755136&lt;br /&gt;
uint32_t pcg32(uint64_t* s) {&lt;br /&gt;
  uint32_t x = ((*s &amp;gt;&amp;gt; 18u) ^ *s) &amp;gt;&amp;gt; 27u;&lt;br /&gt;
  uint32_t r = *s &amp;gt;&amp;gt; 59u;&lt;br /&gt;
  *s  = *s * 6364136223846793005ULL + 1;&lt;br /&gt;
  return (x &amp;gt;&amp;gt; r) | (x &amp;lt;&amp;lt; ((-r) &amp;amp; 31));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* PCG paper: https://www.pcg-random.org/pdf/hmc-cs-2014-0905.pdf&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Gamma&amp;diff=314</id>
		<title>Gamma</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Gamma&amp;diff=314"/>
		<updated>2020-11-28T08:58:47Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quick rules of thumb, since I can never remember which is which:&lt;br /&gt;
* RGB = linear space&lt;br /&gt;
* sRGB = gamma space&lt;br /&gt;
* most image files store sRGB&lt;br /&gt;
* sRGB is unfit for blending&lt;br /&gt;
&lt;br /&gt;
The corollary is:&lt;br /&gt;
* Image files loaded as textures should be converted from sRGB to RGB (but some decoders do this for you!)&lt;br /&gt;
* Since alpha is linear, [[Premultiplied alpha|alpha premultiplication]] should happen in linear space, i.e. after converting to RGB [http://ssp.impulsetrain.com/gamma-premult.html]&lt;br /&gt;
* The shader responsible for putting the final pixels on the screen should have a gamma correction step doing:&lt;br /&gt;
:&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float gamma = 2.2;&lt;br /&gt;
&lt;br /&gt;
out vec4 color;&lt;br /&gt;
&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    color = pow(color, 1. / gamma);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note, however, that OpenGL may also perform this step for you on any on-screen framebuffers (i.e. the default framebuffer) if you do &amp;lt;code&amp;gt;glEnable(GL_FRAMEBUFFER_SRGB)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* https://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-about-gamma/&lt;br /&gt;
* https://stackoverflow.com/questions/23026151/do-i-need-to-gamma-correct-the-final-color-output-on-a-modern-computer-monitor&lt;br /&gt;
* https://www.khronos.org/opengl/wiki/Framebuffer#Colorspace&lt;br /&gt;
* https://en.wikipedia.org/wiki/Gamma_correction&lt;br /&gt;
* https://www.cambridgeincolour.com/tutorials/gamma-correction.htm&lt;br /&gt;
* http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html&lt;br /&gt;
* https://unlimited3d.wordpress.com/2020/01/08/srgb-color-space-in-opengl/&lt;br /&gt;
* https://mynameismjp.wordpress.com/2012/10/24/msaa-overview/ (&amp;quot;Working with HDR and Tone Mapping&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=sRGB&amp;diff=313</id>
		<title>sRGB</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=sRGB&amp;diff=313"/>
		<updated>2020-11-28T07:58:13Z</updated>

		<summary type="html">&lt;p&gt;Vegard: create redirect&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Gamma]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Gamma&amp;diff=312</id>
		<title>Gamma</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Gamma&amp;diff=312"/>
		<updated>2020-11-28T07:57:52Z</updated>

		<summary type="html">&lt;p&gt;Vegard: add link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quick rules of thumb, since I can never remember which is which:&lt;br /&gt;
* RGB = linear space&lt;br /&gt;
* sRGB = gamma space&lt;br /&gt;
* most image files store sRGB&lt;br /&gt;
* sRGB is unfit for blending&lt;br /&gt;
&lt;br /&gt;
The corollary is:&lt;br /&gt;
* Image files loaded as textures should be converted from sRGB to RGB (but some decoders do this for you!)&lt;br /&gt;
* Since alpha is linear, [[Premultiplied alpha|alpha premultiplication]] should happen in linear space, i.e. after converting to RGB [http://ssp.impulsetrain.com/gamma-premult.html]&lt;br /&gt;
* The shader responsible for putting the final pixels on the screen should have a gamma correction step doing:&lt;br /&gt;
:&amp;lt;source lang=&amp;quot;GLSL&amp;quot;&amp;gt;&lt;br /&gt;
const float gamma = 2.2;&lt;br /&gt;
&lt;br /&gt;
out vec4 color;&lt;br /&gt;
&lt;br /&gt;
void main()&lt;br /&gt;
{&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    color = pow(color, 1. / gamma);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note, however, that OpenGL may also perform this step for you on any on-screen framebuffers (i.e. the default framebuffer) if you do &amp;lt;code&amp;gt;glEnable(GL_FRAMEBUFFER_SRGB)&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* https://blog.johnnovak.net/2016/09/21/what-every-coder-should-know-about-gamma/&lt;br /&gt;
* https://stackoverflow.com/questions/23026151/do-i-need-to-gamma-correct-the-final-color-output-on-a-modern-computer-monitor&lt;br /&gt;
* https://www.khronos.org/opengl/wiki/Framebuffer#Colorspace&lt;br /&gt;
* https://en.wikipedia.org/wiki/Gamma_correction&lt;br /&gt;
* https://www.cambridgeincolour.com/tutorials/gamma-correction.htm&lt;br /&gt;
* http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html&lt;br /&gt;
* https://unlimited3d.wordpress.com/2020/01/08/srgb-color-space-in-opengl/&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=B-tree&amp;diff=311</id>
		<title>B-tree</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=B-tree&amp;diff=311"/>
		<updated>2020-10-29T17:17:20Z</updated>

		<summary type="html">&lt;p&gt;Vegard: make it extra clear that I&amp;#039;m not the author&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;By [https://twitter.com/pervognsen/ Per Vognsen]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;assert.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define INLINE inline&lt;br /&gt;
#define CopyMemory memcpy&lt;br /&gt;
#define Allocate malloc&lt;br /&gt;
#define Free free&lt;br /&gt;
#define Assert assert&lt;br /&gt;
&lt;br /&gt;
typedef unsigned int Key;&lt;br /&gt;
typedef unsigned long Value;&lt;br /&gt;
&lt;br /&gt;
// find where to insert the given key to maintain the sorted array&lt;br /&gt;
uint32_t SearchKeys(Key *keys, uint32_t length, Key key)&lt;br /&gt;
{&lt;br /&gt;
    for (uint32_t i = 0; i &amp;lt; length; ++i) {&lt;br /&gt;
        if (key &amp;lt;= keys[i])&lt;br /&gt;
            return i;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return length;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
void Array_Insert(T *array, uint32_t length, uint32_t index, T value)&lt;br /&gt;
{&lt;br /&gt;
    // shift everything up&lt;br /&gt;
    for (uint32_t i = length ; i-- &amp;gt; index; )&lt;br /&gt;
        array[i + 1] = array[i];&lt;br /&gt;
&lt;br /&gt;
    array[index] = value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
void Array_Delete(T *array, uint32_t length, uint32_t index)&lt;br /&gt;
{&lt;br /&gt;
    // shift everything down&lt;br /&gt;
    for (uint32_t i = index + 1; i &amp;lt; length; ++i)&lt;br /&gt;
        array[i - 1] = array[i];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// --- https://gist.github.com/pervognsen/2d48ef9757ee3fd579179239febc817e&lt;br /&gt;
// Per Vognsen, public domain&lt;br /&gt;
&lt;br /&gt;
enum { BMAX = 32, BMIN = BMAX / 2, BHEIGHT = 6 };&lt;br /&gt;
&lt;br /&gt;
struct BNode {&lt;br /&gt;
    uint32_t length;&lt;br /&gt;
    Key keys[BMAX];&lt;br /&gt;
    union {&lt;br /&gt;
        BNode *children[BMAX];&lt;br /&gt;
        Value values[BMAX];&lt;br /&gt;
    };&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static void BNode_Initialize(BNode *node, uint32_t length, Key *keys, void *children) {&lt;br /&gt;
    node-&amp;gt;length = length;&lt;br /&gt;
    CopyMemory(node-&amp;gt;keys, keys, length * sizeof(Key));&lt;br /&gt;
    CopyMemory(node-&amp;gt;children, children, length * sizeof(BNode *));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNode_Create(uint32_t length, Key *keys, void *children) {&lt;br /&gt;
    BNode *node = (BNode *)Allocate(sizeof(BNode));&lt;br /&gt;
    BNode_Initialize(node, length, keys, children);&lt;br /&gt;
    return node;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void BNode_Destroy(BNode *node, uint32_t height) {&lt;br /&gt;
    for (uint32_t index = 0; index &amp;lt; node-&amp;gt;length; index++) {&lt;br /&gt;
        if (height &amp;gt; 1) {&lt;br /&gt;
            BNode_Destroy(node-&amp;gt;children[index], height - 1);&lt;br /&gt;
        }&lt;br /&gt;
        Free(node-&amp;gt;children[index]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static INLINE Key BNode_GetMaxKey(BNode *node) {&lt;br /&gt;
    Assert(node-&amp;gt;length &amp;gt; 0);&lt;br /&gt;
    return node-&amp;gt;keys[node-&amp;gt;length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNodeLeaf_Insert(BNode *leaf, Key key, Value value) {&lt;br /&gt;
    uint32_t index = SearchKeys(leaf-&amp;gt;keys, leaf-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; leaf-&amp;gt;length &amp;amp;&amp;amp; leaf-&amp;gt;keys[index] == key) {&lt;br /&gt;
        leaf-&amp;gt;values[index] = value;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_sibling = 0;&lt;br /&gt;
    if (leaf-&amp;gt;length == BMAX) {&lt;br /&gt;
        new_sibling = BNode_Create(BMIN, leaf-&amp;gt;keys + BMIN, leaf-&amp;gt;values + BMIN);&lt;br /&gt;
        leaf-&amp;gt;length = BMIN;&lt;br /&gt;
        if (index &amp;gt;= BMIN) {&lt;br /&gt;
            leaf = new_sibling;&lt;br /&gt;
            index -= BMIN;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    Array_Insert(leaf-&amp;gt;keys, leaf-&amp;gt;length, index, key);&lt;br /&gt;
    Array_Insert(leaf-&amp;gt;values, leaf-&amp;gt;length, index, value);&lt;br /&gt;
    leaf-&amp;gt;length++;&lt;br /&gt;
    return new_sibling;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNode_Insert(BNode *node, Key key, Value value, uint32_t height) {&lt;br /&gt;
    Assert(height &amp;gt; 0);&lt;br /&gt;
    Assert(node-&amp;gt;length &amp;gt; 0);&lt;br /&gt;
    uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
    if (index == node-&amp;gt;length) {&lt;br /&gt;
        index--;&lt;br /&gt;
        node-&amp;gt;keys[index] = key;&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_child;&lt;br /&gt;
    if (height == 1) {&lt;br /&gt;
        new_child = BNodeLeaf_Insert(node-&amp;gt;children[index], key, value);&lt;br /&gt;
    } else {&lt;br /&gt;
        new_child = BNode_Insert(node-&amp;gt;children[index], key, value, height - 1);&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_sibling = 0;&lt;br /&gt;
    if (new_child) {&lt;br /&gt;
        if (node-&amp;gt;length == BMAX) {&lt;br /&gt;
            new_sibling = BNode_Create(BMIN, node-&amp;gt;keys + BMIN, node-&amp;gt;children + BMIN);&lt;br /&gt;
            node-&amp;gt;length = BMIN;&lt;br /&gt;
            if (index &amp;gt;= BMIN) {&lt;br /&gt;
                node = new_sibling;&lt;br /&gt;
                index -= BMIN;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        node-&amp;gt;keys[index] = BNode_GetMaxKey(node-&amp;gt;children[index]);&lt;br /&gt;
        Array_Insert(node-&amp;gt;keys, node-&amp;gt;length, index + 1, BNode_GetMaxKey(new_child));&lt;br /&gt;
        Array_Insert(node-&amp;gt;children, node-&amp;gt;length, index + 1, new_child);&lt;br /&gt;
        node-&amp;gt;length++;&lt;br /&gt;
    }&lt;br /&gt;
    return new_sibling;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static bool BNodeLeaf_Delete(BNode *leaf, Key key) {&lt;br /&gt;
    uint32_t index = SearchKeys(leaf-&amp;gt;keys, leaf-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; leaf-&amp;gt;length &amp;amp;&amp;amp; leaf-&amp;gt;keys[index] == key) {&lt;br /&gt;
        Array_Delete(leaf-&amp;gt;keys, leaf-&amp;gt;length, index);&lt;br /&gt;
        Array_Delete(leaf-&amp;gt;values, leaf-&amp;gt;length, index);&lt;br /&gt;
        leaf-&amp;gt;length--;&lt;br /&gt;
        return leaf-&amp;gt;length == 0;&lt;br /&gt;
    }&lt;br /&gt;
    return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void BNode_Delete(BNode *node, Key key, uint32_t height) {&lt;br /&gt;
    Assert(height &amp;gt; 0);&lt;br /&gt;
    uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; node-&amp;gt;length) {&lt;br /&gt;
        if (height == 1) {&lt;br /&gt;
            if (BNodeLeaf_Delete(node-&amp;gt;children[index], key) &amp;amp;&amp;amp; node-&amp;gt;length &amp;gt; 1) {&lt;br /&gt;
                Free(node-&amp;gt;children[index]);&lt;br /&gt;
                Array_Delete(node-&amp;gt;keys, node-&amp;gt;length, index);&lt;br /&gt;
                Array_Delete(node-&amp;gt;children, node-&amp;gt;length, index);&lt;br /&gt;
                node-&amp;gt;length--;&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            BNode_Delete(node-&amp;gt;children[index], key, height - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct BTree {&lt;br /&gt;
    uint32_t height;&lt;br /&gt;
    BNode root;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void BTree_Initialize(BTree *tree) {&lt;br /&gt;
    Assert(BMAX == 2 * BMIN);&lt;br /&gt;
    Assert(sizeof(BNode *) == sizeof(Value));&lt;br /&gt;
    tree-&amp;gt;height = 0;&lt;br /&gt;
    tree-&amp;gt;root.length = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Destroy(BTree *tree) {&lt;br /&gt;
    if (tree-&amp;gt;height &amp;gt; 0) {&lt;br /&gt;
        BNode_Destroy(&amp;amp;tree-&amp;gt;root, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Value *BTree_Find(BTree *tree, Key key) {&lt;br /&gt;
    uint32_t height = tree-&amp;gt;height;&lt;br /&gt;
    BNode *node = &amp;amp;tree-&amp;gt;root;&lt;br /&gt;
    for (;;) {&lt;br /&gt;
        uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
        if (index == node-&amp;gt;length) {&lt;br /&gt;
            return 0;&lt;br /&gt;
        }&lt;br /&gt;
        if (height == 0) {&lt;br /&gt;
            return (node-&amp;gt;keys[index] == key) ? (node-&amp;gt;values + index) : 0;&lt;br /&gt;
        }&lt;br /&gt;
        height--;&lt;br /&gt;
        node = node-&amp;gt;children[index];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Insert(BTree *tree, Key key, Value value) {&lt;br /&gt;
    BNode *root = &amp;amp;tree-&amp;gt;root;&lt;br /&gt;
    BNode *new_root_sibling;&lt;br /&gt;
    if (tree-&amp;gt;height == 0) {&lt;br /&gt;
        new_root_sibling = BNodeLeaf_Insert(root, key, value);&lt;br /&gt;
    } else {&lt;br /&gt;
        new_root_sibling = BNode_Insert(root, key, value, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
    if (new_root_sibling) {&lt;br /&gt;
        BNode *old_root = BNode_Create(root-&amp;gt;length, root-&amp;gt;keys, root-&amp;gt;children);&lt;br /&gt;
        Key keys[2] = {BNode_GetMaxKey(old_root), BNode_GetMaxKey(new_root_sibling)};&lt;br /&gt;
        BNode *children[2] = {old_root, new_root_sibling};&lt;br /&gt;
        BNode_Initialize(root, 2, keys, children);&lt;br /&gt;
        tree-&amp;gt;height++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Delete(BTree *tree, Key key) {&lt;br /&gt;
    if (tree-&amp;gt;height == 0) {&lt;br /&gt;
        BNodeLeaf_Delete(&amp;amp;tree-&amp;gt;root, key);&lt;br /&gt;
    } else {&lt;br /&gt;
        BNode_Delete(&amp;amp;tree-&amp;gt;root, key, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== See also ===&lt;br /&gt;
* https://gist.github.com/pervognsen/2d48ef9757ee3fd579179239febc817e&lt;br /&gt;
&lt;br /&gt;
[[Category:Programming]]&lt;br /&gt;
[[Category:C++]]&lt;br /&gt;
[[Category:Data structures]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=B-tree&amp;diff=310</id>
		<title>B-tree</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=B-tree&amp;diff=310"/>
		<updated>2020-10-29T17:15:12Z</updated>

		<summary type="html">&lt;p&gt;Vegard: make source clearer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;source lang=&amp;quot;C++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;assert.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define INLINE inline&lt;br /&gt;
#define CopyMemory memcpy&lt;br /&gt;
#define Allocate malloc&lt;br /&gt;
#define Free free&lt;br /&gt;
#define Assert assert&lt;br /&gt;
&lt;br /&gt;
typedef unsigned int Key;&lt;br /&gt;
typedef unsigned long Value;&lt;br /&gt;
&lt;br /&gt;
// find where to insert the given key to maintain the sorted array&lt;br /&gt;
uint32_t SearchKeys(Key *keys, uint32_t length, Key key)&lt;br /&gt;
{&lt;br /&gt;
    for (uint32_t i = 0; i &amp;lt; length; ++i) {&lt;br /&gt;
        if (key &amp;lt;= keys[i])&lt;br /&gt;
            return i;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return length;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
void Array_Insert(T *array, uint32_t length, uint32_t index, T value)&lt;br /&gt;
{&lt;br /&gt;
    // shift everything up&lt;br /&gt;
    for (uint32_t i = length ; i-- &amp;gt; index; )&lt;br /&gt;
        array[i + 1] = array[i];&lt;br /&gt;
&lt;br /&gt;
    array[index] = value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
void Array_Delete(T *array, uint32_t length, uint32_t index)&lt;br /&gt;
{&lt;br /&gt;
    // shift everything down&lt;br /&gt;
    for (uint32_t i = index + 1; i &amp;lt; length; ++i)&lt;br /&gt;
        array[i - 1] = array[i];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// --- https://gist.github.com/pervognsen/2d48ef9757ee3fd579179239febc817e&lt;br /&gt;
// Per Vognsen, public domain&lt;br /&gt;
&lt;br /&gt;
enum { BMAX = 32, BMIN = BMAX / 2, BHEIGHT = 6 };&lt;br /&gt;
&lt;br /&gt;
struct BNode {&lt;br /&gt;
    uint32_t length;&lt;br /&gt;
    Key keys[BMAX];&lt;br /&gt;
    union {&lt;br /&gt;
        BNode *children[BMAX];&lt;br /&gt;
        Value values[BMAX];&lt;br /&gt;
    };&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static void BNode_Initialize(BNode *node, uint32_t length, Key *keys, void *children) {&lt;br /&gt;
    node-&amp;gt;length = length;&lt;br /&gt;
    CopyMemory(node-&amp;gt;keys, keys, length * sizeof(Key));&lt;br /&gt;
    CopyMemory(node-&amp;gt;children, children, length * sizeof(BNode *));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNode_Create(uint32_t length, Key *keys, void *children) {&lt;br /&gt;
    BNode *node = (BNode *)Allocate(sizeof(BNode));&lt;br /&gt;
    BNode_Initialize(node, length, keys, children);&lt;br /&gt;
    return node;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void BNode_Destroy(BNode *node, uint32_t height) {&lt;br /&gt;
    for (uint32_t index = 0; index &amp;lt; node-&amp;gt;length; index++) {&lt;br /&gt;
        if (height &amp;gt; 1) {&lt;br /&gt;
            BNode_Destroy(node-&amp;gt;children[index], height - 1);&lt;br /&gt;
        }&lt;br /&gt;
        Free(node-&amp;gt;children[index]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static INLINE Key BNode_GetMaxKey(BNode *node) {&lt;br /&gt;
    Assert(node-&amp;gt;length &amp;gt; 0);&lt;br /&gt;
    return node-&amp;gt;keys[node-&amp;gt;length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNodeLeaf_Insert(BNode *leaf, Key key, Value value) {&lt;br /&gt;
    uint32_t index = SearchKeys(leaf-&amp;gt;keys, leaf-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; leaf-&amp;gt;length &amp;amp;&amp;amp; leaf-&amp;gt;keys[index] == key) {&lt;br /&gt;
        leaf-&amp;gt;values[index] = value;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_sibling = 0;&lt;br /&gt;
    if (leaf-&amp;gt;length == BMAX) {&lt;br /&gt;
        new_sibling = BNode_Create(BMIN, leaf-&amp;gt;keys + BMIN, leaf-&amp;gt;values + BMIN);&lt;br /&gt;
        leaf-&amp;gt;length = BMIN;&lt;br /&gt;
        if (index &amp;gt;= BMIN) {&lt;br /&gt;
            leaf = new_sibling;&lt;br /&gt;
            index -= BMIN;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    Array_Insert(leaf-&amp;gt;keys, leaf-&amp;gt;length, index, key);&lt;br /&gt;
    Array_Insert(leaf-&amp;gt;values, leaf-&amp;gt;length, index, value);&lt;br /&gt;
    leaf-&amp;gt;length++;&lt;br /&gt;
    return new_sibling;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNode_Insert(BNode *node, Key key, Value value, uint32_t height) {&lt;br /&gt;
    Assert(height &amp;gt; 0);&lt;br /&gt;
    Assert(node-&amp;gt;length &amp;gt; 0);&lt;br /&gt;
    uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
    if (index == node-&amp;gt;length) {&lt;br /&gt;
        index--;&lt;br /&gt;
        node-&amp;gt;keys[index] = key;&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_child;&lt;br /&gt;
    if (height == 1) {&lt;br /&gt;
        new_child = BNodeLeaf_Insert(node-&amp;gt;children[index], key, value);&lt;br /&gt;
    } else {&lt;br /&gt;
        new_child = BNode_Insert(node-&amp;gt;children[index], key, value, height - 1);&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_sibling = 0;&lt;br /&gt;
    if (new_child) {&lt;br /&gt;
        if (node-&amp;gt;length == BMAX) {&lt;br /&gt;
            new_sibling = BNode_Create(BMIN, node-&amp;gt;keys + BMIN, node-&amp;gt;children + BMIN);&lt;br /&gt;
            node-&amp;gt;length = BMIN;&lt;br /&gt;
            if (index &amp;gt;= BMIN) {&lt;br /&gt;
                node = new_sibling;&lt;br /&gt;
                index -= BMIN;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        node-&amp;gt;keys[index] = BNode_GetMaxKey(node-&amp;gt;children[index]);&lt;br /&gt;
        Array_Insert(node-&amp;gt;keys, node-&amp;gt;length, index + 1, BNode_GetMaxKey(new_child));&lt;br /&gt;
        Array_Insert(node-&amp;gt;children, node-&amp;gt;length, index + 1, new_child);&lt;br /&gt;
        node-&amp;gt;length++;&lt;br /&gt;
    }&lt;br /&gt;
    return new_sibling;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static bool BNodeLeaf_Delete(BNode *leaf, Key key) {&lt;br /&gt;
    uint32_t index = SearchKeys(leaf-&amp;gt;keys, leaf-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; leaf-&amp;gt;length &amp;amp;&amp;amp; leaf-&amp;gt;keys[index] == key) {&lt;br /&gt;
        Array_Delete(leaf-&amp;gt;keys, leaf-&amp;gt;length, index);&lt;br /&gt;
        Array_Delete(leaf-&amp;gt;values, leaf-&amp;gt;length, index);&lt;br /&gt;
        leaf-&amp;gt;length--;&lt;br /&gt;
        return leaf-&amp;gt;length == 0;&lt;br /&gt;
    }&lt;br /&gt;
    return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void BNode_Delete(BNode *node, Key key, uint32_t height) {&lt;br /&gt;
    Assert(height &amp;gt; 0);&lt;br /&gt;
    uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; node-&amp;gt;length) {&lt;br /&gt;
        if (height == 1) {&lt;br /&gt;
            if (BNodeLeaf_Delete(node-&amp;gt;children[index], key) &amp;amp;&amp;amp; node-&amp;gt;length &amp;gt; 1) {&lt;br /&gt;
                Free(node-&amp;gt;children[index]);&lt;br /&gt;
                Array_Delete(node-&amp;gt;keys, node-&amp;gt;length, index);&lt;br /&gt;
                Array_Delete(node-&amp;gt;children, node-&amp;gt;length, index);&lt;br /&gt;
                node-&amp;gt;length--;&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            BNode_Delete(node-&amp;gt;children[index], key, height - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct BTree {&lt;br /&gt;
    uint32_t height;&lt;br /&gt;
    BNode root;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void BTree_Initialize(BTree *tree) {&lt;br /&gt;
    Assert(BMAX == 2 * BMIN);&lt;br /&gt;
    Assert(sizeof(BNode *) == sizeof(Value));&lt;br /&gt;
    tree-&amp;gt;height = 0;&lt;br /&gt;
    tree-&amp;gt;root.length = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Destroy(BTree *tree) {&lt;br /&gt;
    if (tree-&amp;gt;height &amp;gt; 0) {&lt;br /&gt;
        BNode_Destroy(&amp;amp;tree-&amp;gt;root, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Value *BTree_Find(BTree *tree, Key key) {&lt;br /&gt;
    uint32_t height = tree-&amp;gt;height;&lt;br /&gt;
    BNode *node = &amp;amp;tree-&amp;gt;root;&lt;br /&gt;
    for (;;) {&lt;br /&gt;
        uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
        if (index == node-&amp;gt;length) {&lt;br /&gt;
            return 0;&lt;br /&gt;
        }&lt;br /&gt;
        if (height == 0) {&lt;br /&gt;
            return (node-&amp;gt;keys[index] == key) ? (node-&amp;gt;values + index) : 0;&lt;br /&gt;
        }&lt;br /&gt;
        height--;&lt;br /&gt;
        node = node-&amp;gt;children[index];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Insert(BTree *tree, Key key, Value value) {&lt;br /&gt;
    BNode *root = &amp;amp;tree-&amp;gt;root;&lt;br /&gt;
    BNode *new_root_sibling;&lt;br /&gt;
    if (tree-&amp;gt;height == 0) {&lt;br /&gt;
        new_root_sibling = BNodeLeaf_Insert(root, key, value);&lt;br /&gt;
    } else {&lt;br /&gt;
        new_root_sibling = BNode_Insert(root, key, value, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
    if (new_root_sibling) {&lt;br /&gt;
        BNode *old_root = BNode_Create(root-&amp;gt;length, root-&amp;gt;keys, root-&amp;gt;children);&lt;br /&gt;
        Key keys[2] = {BNode_GetMaxKey(old_root), BNode_GetMaxKey(new_root_sibling)};&lt;br /&gt;
        BNode *children[2] = {old_root, new_root_sibling};&lt;br /&gt;
        BNode_Initialize(root, 2, keys, children);&lt;br /&gt;
        tree-&amp;gt;height++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Delete(BTree *tree, Key key) {&lt;br /&gt;
    if (tree-&amp;gt;height == 0) {&lt;br /&gt;
        BNodeLeaf_Delete(&amp;amp;tree-&amp;gt;root, key);&lt;br /&gt;
    } else {&lt;br /&gt;
        BNode_Delete(&amp;amp;tree-&amp;gt;root, key, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== See also ===&lt;br /&gt;
* https://gist.github.com/pervognsen/2d48ef9757ee3fd579179239febc817e&lt;br /&gt;
&lt;br /&gt;
[[Category:Programming]]&lt;br /&gt;
[[Category:C++]]&lt;br /&gt;
[[Category:Data structures]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=B-tree&amp;diff=309</id>
		<title>B-tree</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=B-tree&amp;diff=309"/>
		<updated>2020-10-29T17:14:20Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;source lang=&amp;quot;C++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;assert.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdint.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;
#include &amp;lt;string.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
#define INLINE inline&lt;br /&gt;
#define CopyMemory memcpy&lt;br /&gt;
#define Allocate malloc&lt;br /&gt;
#define Free free&lt;br /&gt;
#define Assert assert&lt;br /&gt;
&lt;br /&gt;
typedef unsigned int Key;&lt;br /&gt;
typedef unsigned long Value;&lt;br /&gt;
&lt;br /&gt;
// find where to insert the given key to maintain the sorted array&lt;br /&gt;
uint32_t SearchKeys(Key *keys, uint32_t length, Key key)&lt;br /&gt;
{&lt;br /&gt;
    for (uint32_t i = 0; i &amp;lt; length; ++i) {&lt;br /&gt;
        if (key &amp;lt;= keys[i])&lt;br /&gt;
            return i;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return length;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
void Array_Insert(T *array, uint32_t length, uint32_t index, T value)&lt;br /&gt;
{&lt;br /&gt;
    // shift everything up&lt;br /&gt;
    for (uint32_t i = length ; i-- &amp;gt; index; )&lt;br /&gt;
        array[i + 1] = array[i];&lt;br /&gt;
&lt;br /&gt;
    array[index] = value;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
template&amp;lt;typename T&amp;gt;&lt;br /&gt;
void Array_Delete(T *array, uint32_t length, uint32_t index)&lt;br /&gt;
{&lt;br /&gt;
    // shift everything down&lt;br /&gt;
    for (uint32_t i = index + 1; i &amp;lt; length; ++i)&lt;br /&gt;
        array[i - 1] = array[i];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// --- https://gist.github.com/pervognsen/2d48ef9757ee3fd579179239febc817e&lt;br /&gt;
// Per Vognsen, public domain&lt;br /&gt;
&lt;br /&gt;
enum { BMAX = 32, BMIN = BMAX / 2, BHEIGHT = 6 };&lt;br /&gt;
&lt;br /&gt;
struct BNode {&lt;br /&gt;
    uint32_t length;&lt;br /&gt;
    Key keys[BMAX];&lt;br /&gt;
    union {&lt;br /&gt;
        BNode *children[BMAX];&lt;br /&gt;
        Value values[BMAX];&lt;br /&gt;
    };&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
static void BNode_Initialize(BNode *node, uint32_t length, Key *keys, void *children) {&lt;br /&gt;
    node-&amp;gt;length = length;&lt;br /&gt;
    CopyMemory(node-&amp;gt;keys, keys, length * sizeof(Key));&lt;br /&gt;
    CopyMemory(node-&amp;gt;children, children, length * sizeof(BNode *));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNode_Create(uint32_t length, Key *keys, void *children) {&lt;br /&gt;
    BNode *node = (BNode *)Allocate(sizeof(BNode));&lt;br /&gt;
    BNode_Initialize(node, length, keys, children);&lt;br /&gt;
    return node;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void BNode_Destroy(BNode *node, uint32_t height) {&lt;br /&gt;
    for (uint32_t index = 0; index &amp;lt; node-&amp;gt;length; index++) {&lt;br /&gt;
        if (height &amp;gt; 1) {&lt;br /&gt;
            BNode_Destroy(node-&amp;gt;children[index], height - 1);&lt;br /&gt;
        }&lt;br /&gt;
        Free(node-&amp;gt;children[index]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static INLINE Key BNode_GetMaxKey(BNode *node) {&lt;br /&gt;
    Assert(node-&amp;gt;length &amp;gt; 0);&lt;br /&gt;
    return node-&amp;gt;keys[node-&amp;gt;length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNodeLeaf_Insert(BNode *leaf, Key key, Value value) {&lt;br /&gt;
    uint32_t index = SearchKeys(leaf-&amp;gt;keys, leaf-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; leaf-&amp;gt;length &amp;amp;&amp;amp; leaf-&amp;gt;keys[index] == key) {&lt;br /&gt;
        leaf-&amp;gt;values[index] = value;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_sibling = 0;&lt;br /&gt;
    if (leaf-&amp;gt;length == BMAX) {&lt;br /&gt;
        new_sibling = BNode_Create(BMIN, leaf-&amp;gt;keys + BMIN, leaf-&amp;gt;values + BMIN);&lt;br /&gt;
        leaf-&amp;gt;length = BMIN;&lt;br /&gt;
        if (index &amp;gt;= BMIN) {&lt;br /&gt;
            leaf = new_sibling;&lt;br /&gt;
            index -= BMIN;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    Array_Insert(leaf-&amp;gt;keys, leaf-&amp;gt;length, index, key);&lt;br /&gt;
    Array_Insert(leaf-&amp;gt;values, leaf-&amp;gt;length, index, value);&lt;br /&gt;
    leaf-&amp;gt;length++;&lt;br /&gt;
    return new_sibling;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static BNode *BNode_Insert(BNode *node, Key key, Value value, uint32_t height) {&lt;br /&gt;
    Assert(height &amp;gt; 0);&lt;br /&gt;
    Assert(node-&amp;gt;length &amp;gt; 0);&lt;br /&gt;
    uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
    if (index == node-&amp;gt;length) {&lt;br /&gt;
        index--;&lt;br /&gt;
        node-&amp;gt;keys[index] = key;&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_child;&lt;br /&gt;
    if (height == 1) {&lt;br /&gt;
        new_child = BNodeLeaf_Insert(node-&amp;gt;children[index], key, value);&lt;br /&gt;
    } else {&lt;br /&gt;
        new_child = BNode_Insert(node-&amp;gt;children[index], key, value, height - 1);&lt;br /&gt;
    }&lt;br /&gt;
    BNode *new_sibling = 0;&lt;br /&gt;
    if (new_child) {&lt;br /&gt;
        if (node-&amp;gt;length == BMAX) {&lt;br /&gt;
            new_sibling = BNode_Create(BMIN, node-&amp;gt;keys + BMIN, node-&amp;gt;children + BMIN);&lt;br /&gt;
            node-&amp;gt;length = BMIN;&lt;br /&gt;
            if (index &amp;gt;= BMIN) {&lt;br /&gt;
                node = new_sibling;&lt;br /&gt;
                index -= BMIN;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        node-&amp;gt;keys[index] = BNode_GetMaxKey(node-&amp;gt;children[index]);&lt;br /&gt;
        Array_Insert(node-&amp;gt;keys, node-&amp;gt;length, index + 1, BNode_GetMaxKey(new_child));&lt;br /&gt;
        Array_Insert(node-&amp;gt;children, node-&amp;gt;length, index + 1, new_child);&lt;br /&gt;
        node-&amp;gt;length++;&lt;br /&gt;
    }&lt;br /&gt;
    return new_sibling;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static bool BNodeLeaf_Delete(BNode *leaf, Key key) {&lt;br /&gt;
    uint32_t index = SearchKeys(leaf-&amp;gt;keys, leaf-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; leaf-&amp;gt;length &amp;amp;&amp;amp; leaf-&amp;gt;keys[index] == key) {&lt;br /&gt;
        Array_Delete(leaf-&amp;gt;keys, leaf-&amp;gt;length, index);&lt;br /&gt;
        Array_Delete(leaf-&amp;gt;values, leaf-&amp;gt;length, index);&lt;br /&gt;
        leaf-&amp;gt;length--;&lt;br /&gt;
        return leaf-&amp;gt;length == 0;&lt;br /&gt;
    }&lt;br /&gt;
    return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static void BNode_Delete(BNode *node, Key key, uint32_t height) {&lt;br /&gt;
    Assert(height &amp;gt; 0);&lt;br /&gt;
    uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
    if (index &amp;lt; node-&amp;gt;length) {&lt;br /&gt;
        if (height == 1) {&lt;br /&gt;
            if (BNodeLeaf_Delete(node-&amp;gt;children[index], key) &amp;amp;&amp;amp; node-&amp;gt;length &amp;gt; 1) {&lt;br /&gt;
                Free(node-&amp;gt;children[index]);&lt;br /&gt;
                Array_Delete(node-&amp;gt;keys, node-&amp;gt;length, index);&lt;br /&gt;
                Array_Delete(node-&amp;gt;children, node-&amp;gt;length, index);&lt;br /&gt;
                node-&amp;gt;length--;&lt;br /&gt;
            }&lt;br /&gt;
        } else {&lt;br /&gt;
            BNode_Delete(node-&amp;gt;children[index], key, height - 1);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
struct BTree {&lt;br /&gt;
    uint32_t height;&lt;br /&gt;
    BNode root;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
void BTree_Initialize(BTree *tree) {&lt;br /&gt;
    Assert(BMAX == 2 * BMIN);&lt;br /&gt;
    Assert(sizeof(BNode *) == sizeof(Value));&lt;br /&gt;
    tree-&amp;gt;height = 0;&lt;br /&gt;
    tree-&amp;gt;root.length = 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Destroy(BTree *tree) {&lt;br /&gt;
    if (tree-&amp;gt;height &amp;gt; 0) {&lt;br /&gt;
        BNode_Destroy(&amp;amp;tree-&amp;gt;root, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Value *BTree_Find(BTree *tree, Key key) {&lt;br /&gt;
    uint32_t height = tree-&amp;gt;height;&lt;br /&gt;
    BNode *node = &amp;amp;tree-&amp;gt;root;&lt;br /&gt;
    for (;;) {&lt;br /&gt;
        uint32_t index = SearchKeys(node-&amp;gt;keys, node-&amp;gt;length, key);&lt;br /&gt;
        if (index == node-&amp;gt;length) {&lt;br /&gt;
            return 0;&lt;br /&gt;
        }&lt;br /&gt;
        if (height == 0) {&lt;br /&gt;
            return (node-&amp;gt;keys[index] == key) ? (node-&amp;gt;values + index) : 0;&lt;br /&gt;
        }&lt;br /&gt;
        height--;&lt;br /&gt;
        node = node-&amp;gt;children[index];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Insert(BTree *tree, Key key, Value value) {&lt;br /&gt;
    BNode *root = &amp;amp;tree-&amp;gt;root;&lt;br /&gt;
    BNode *new_root_sibling;&lt;br /&gt;
    if (tree-&amp;gt;height == 0) {&lt;br /&gt;
        new_root_sibling = BNodeLeaf_Insert(root, key, value);&lt;br /&gt;
    } else {&lt;br /&gt;
        new_root_sibling = BNode_Insert(root, key, value, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
    if (new_root_sibling) {&lt;br /&gt;
        BNode *old_root = BNode_Create(root-&amp;gt;length, root-&amp;gt;keys, root-&amp;gt;children);&lt;br /&gt;
        Key keys[2] = {BNode_GetMaxKey(old_root), BNode_GetMaxKey(new_root_sibling)};&lt;br /&gt;
        BNode *children[2] = {old_root, new_root_sibling};&lt;br /&gt;
        BNode_Initialize(root, 2, keys, children);&lt;br /&gt;
        tree-&amp;gt;height++;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
void BTree_Delete(BTree *tree, Key key) {&lt;br /&gt;
    if (tree-&amp;gt;height == 0) {&lt;br /&gt;
        BNodeLeaf_Delete(&amp;amp;tree-&amp;gt;root, key);&lt;br /&gt;
    } else {&lt;br /&gt;
        BNode_Delete(&amp;amp;tree-&amp;gt;root, key, tree-&amp;gt;height);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Programming]]&lt;br /&gt;
[[Category:C++]]&lt;br /&gt;
[[Category:Data structures]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Fur_shells&amp;diff=308</id>
		<title>Fur shells</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Fur_shells&amp;diff=308"/>
		<updated>2020-10-11T19:25:53Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
See: https://twitter.com/MarioBrothBlog/status/1314996377605361664&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Frame_analysis&amp;diff=307</id>
		<title>Frame analysis</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Frame_analysis&amp;diff=307"/>
		<updated>2020-09-08T21:23:24Z</updated>

		<summary type="html">&lt;p&gt;Vegard: Doom Eternal&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a list of &amp;quot;frame analysis&amp;quot; blog posts, i.e. posts which dissect how a game does its rendering.&lt;br /&gt;
&lt;br /&gt;
== Engines ==&lt;br /&gt;
&lt;br /&gt;
=== AnKi 3D ===&lt;br /&gt;
&lt;br /&gt;
* http://anki3d.org/anatomy-of-a-frame-in-anki/&lt;br /&gt;
&lt;br /&gt;
== Games ==&lt;br /&gt;
&lt;br /&gt;
=== A Plague Tale: Innocence ===&lt;br /&gt;
&lt;br /&gt;
* https://gamingbolt.com/a-plague-tale-innocence-graphics-analysis-one-of-the-best-looking-games-of-this-gen&lt;br /&gt;
&lt;br /&gt;
=== Batman: Arkham Knight ===&lt;br /&gt;
&lt;br /&gt;
* http://morad.in/2020/04/03/unmasking-arkham-knight/&lt;br /&gt;
&lt;br /&gt;
=== Battlefield 3 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.slideshare.net/DICEStudio/directx-11-rendering-in-battlefield-3&lt;br /&gt;
&lt;br /&gt;
=== Battlefield 4 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.slideshare.net/DevCentralAMD/rendering-battlefield-4-with-mantle-yuriy-o-donnell&lt;br /&gt;
&lt;br /&gt;
=== BioShock Infinite ===&lt;br /&gt;
&lt;br /&gt;
* https://solid-angle.blogspot.com/2014/03/bioshock-infinite-lighting.html&lt;br /&gt;
&lt;br /&gt;
=== Castlevania: Lords of Shadow 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.elopezr.com/castlevania-lords-of-shadow-2-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Deus Ex: Human Revolution ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/03/10/deus-ex-human-revolution-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Doom 2016 ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2016/09/09/doom-2016-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Doom Eternal ===&lt;br /&gt;
* https://simoncoenen.com/blog/programming/graphics/DoomEternalStudy.html&lt;br /&gt;
&lt;br /&gt;
=== Far Cry 5 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.gdcvault.com/play/1025480/Terrain-Rendering-in-Far-Cry&lt;br /&gt;
&lt;br /&gt;
=== Gears of War 5 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.eurogamer.net/articles/digitalfoundry-2019-gears-5-tech-interview&lt;br /&gt;
&lt;br /&gt;
=== Ghost of Tsushima ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.selfshadow.com/publications/s2020-shading-course/patry/slides/&lt;br /&gt;
&lt;br /&gt;
=== GTA V ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Killzone 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.guerrilla-games.com/read/deferred-rendering-in-killzone-2&lt;br /&gt;
&lt;br /&gt;
=== League of Legends ===&lt;br /&gt;
&lt;br /&gt;
* https://technology.riotgames.com/news/trip-down-lol-graphics-pipeline&lt;br /&gt;
&lt;br /&gt;
=== Metal Gear Solid V ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2017/12/15/mgs-v-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Metro Exodus ===&lt;br /&gt;
&lt;br /&gt;
* https://aschrein.github.io/2019/08/11/metro_breakdown.html&lt;br /&gt;
&lt;br /&gt;
=== Middle Earth: Shadow of Mordor ===&lt;br /&gt;
&lt;br /&gt;
* http://www.elopezr.com/the-rendering-of-middle-earth-shadow-of-mordor/&lt;br /&gt;
&lt;br /&gt;
=== Ni No Kuni 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.thomaspoulet.fr/ninokuni2-frame/&lt;br /&gt;
&lt;br /&gt;
=== Red Dead Redemption 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://imgeself.github.io/posts/2020-06-19-graphics-study-rdr2/&lt;br /&gt;
&lt;br /&gt;
=== Resident Evil 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://aschrein.github.io/2019/08/01/re2_breakdown.html&lt;br /&gt;
&lt;br /&gt;
=== Rise of the Tomb Raider ===&lt;br /&gt;
&lt;br /&gt;
* http://www.elopezr.com/the-rendering-of-rise-of-the-tomb-raider/&lt;br /&gt;
&lt;br /&gt;
=== Supreme Commander ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/06/23/supreme-commander-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== The Witcher 3 ===&lt;br /&gt;
&lt;br /&gt;
* https://astralcode.blogspot.com/2018/11/reverse-engineering-rendering-of.html&lt;br /&gt;
&lt;br /&gt;
=== The Witness ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.thomaspoulet.fr/the-witness-frame-part-1/&lt;br /&gt;
* https://blog.thomaspoulet.fr/the-witness-frame-part-2/&lt;br /&gt;
&lt;br /&gt;
=== Total War ===&lt;br /&gt;
&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-2/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-3/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-4/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-5/&lt;br /&gt;
&lt;br /&gt;
=== Wind Waker ===&lt;br /&gt;
&lt;br /&gt;
* https://polycount.com/discussion/104415/zelda-wind-waker-tech-and-texture-analysis-picture-heavy&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Frame_analysis&amp;diff=306</id>
		<title>Frame analysis</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Frame_analysis&amp;diff=306"/>
		<updated>2020-09-01T13:21:16Z</updated>

		<summary type="html">&lt;p&gt;Vegard: Ghost of Tsushima&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a list of &amp;quot;frame analysis&amp;quot; blog posts, i.e. posts which dissect how a game does its rendering.&lt;br /&gt;
&lt;br /&gt;
== Engines ==&lt;br /&gt;
&lt;br /&gt;
=== AnKi 3D ===&lt;br /&gt;
&lt;br /&gt;
* http://anki3d.org/anatomy-of-a-frame-in-anki/&lt;br /&gt;
&lt;br /&gt;
== Games ==&lt;br /&gt;
&lt;br /&gt;
=== A Plague Tale: Innocence ===&lt;br /&gt;
&lt;br /&gt;
* https://gamingbolt.com/a-plague-tale-innocence-graphics-analysis-one-of-the-best-looking-games-of-this-gen&lt;br /&gt;
&lt;br /&gt;
=== Batman: Arkham Knight ===&lt;br /&gt;
&lt;br /&gt;
* http://morad.in/2020/04/03/unmasking-arkham-knight/&lt;br /&gt;
&lt;br /&gt;
=== Battlefield 3 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.slideshare.net/DICEStudio/directx-11-rendering-in-battlefield-3&lt;br /&gt;
&lt;br /&gt;
=== Battlefield 4 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.slideshare.net/DevCentralAMD/rendering-battlefield-4-with-mantle-yuriy-o-donnell&lt;br /&gt;
&lt;br /&gt;
=== BioShock Infinite ===&lt;br /&gt;
&lt;br /&gt;
* https://solid-angle.blogspot.com/2014/03/bioshock-infinite-lighting.html&lt;br /&gt;
&lt;br /&gt;
=== Castlevania: Lords of Shadow 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.elopezr.com/castlevania-lords-of-shadow-2-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Deus Ex: Human Revolution ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/03/10/deus-ex-human-revolution-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Doom 2016 ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2016/09/09/doom-2016-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Far Cry 5 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.gdcvault.com/play/1025480/Terrain-Rendering-in-Far-Cry&lt;br /&gt;
&lt;br /&gt;
=== Gears of War 5 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.eurogamer.net/articles/digitalfoundry-2019-gears-5-tech-interview&lt;br /&gt;
&lt;br /&gt;
=== Ghost of Tsushima ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.selfshadow.com/publications/s2020-shading-course/patry/slides/&lt;br /&gt;
&lt;br /&gt;
=== GTA V ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Killzone 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.guerrilla-games.com/read/deferred-rendering-in-killzone-2&lt;br /&gt;
&lt;br /&gt;
=== League of Legends ===&lt;br /&gt;
&lt;br /&gt;
* https://technology.riotgames.com/news/trip-down-lol-graphics-pipeline&lt;br /&gt;
&lt;br /&gt;
=== Metal Gear Solid V ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2017/12/15/mgs-v-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Metro Exodus ===&lt;br /&gt;
&lt;br /&gt;
* https://aschrein.github.io/2019/08/11/metro_breakdown.html&lt;br /&gt;
&lt;br /&gt;
=== Middle Earth: Shadow of Mordor ===&lt;br /&gt;
&lt;br /&gt;
* http://www.elopezr.com/the-rendering-of-middle-earth-shadow-of-mordor/&lt;br /&gt;
&lt;br /&gt;
=== Ni No Kuni 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.thomaspoulet.fr/ninokuni2-frame/&lt;br /&gt;
&lt;br /&gt;
=== Red Dead Redemption 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://imgeself.github.io/posts/2020-06-19-graphics-study-rdr2/&lt;br /&gt;
&lt;br /&gt;
=== Resident Evil 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://aschrein.github.io/2019/08/01/re2_breakdown.html&lt;br /&gt;
&lt;br /&gt;
=== Rise of the Tomb Raider ===&lt;br /&gt;
&lt;br /&gt;
* http://www.elopezr.com/the-rendering-of-rise-of-the-tomb-raider/&lt;br /&gt;
&lt;br /&gt;
=== Supreme Commander ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/06/23/supreme-commander-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== The Witcher 3 ===&lt;br /&gt;
&lt;br /&gt;
* https://astralcode.blogspot.com/2018/11/reverse-engineering-rendering-of.html&lt;br /&gt;
&lt;br /&gt;
=== The Witness ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.thomaspoulet.fr/the-witness-frame-part-1/&lt;br /&gt;
* https://blog.thomaspoulet.fr/the-witness-frame-part-2/&lt;br /&gt;
&lt;br /&gt;
=== Total War ===&lt;br /&gt;
&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-2/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-3/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-4/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-5/&lt;br /&gt;
&lt;br /&gt;
=== Wind Waker ===&lt;br /&gt;
&lt;br /&gt;
* https://polycount.com/discussion/104415/zelda-wind-waker-tech-and-texture-analysis-picture-heavy&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Frame_analysis&amp;diff=305</id>
		<title>Frame analysis</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Frame_analysis&amp;diff=305"/>
		<updated>2020-06-24T19:10:23Z</updated>

		<summary type="html">&lt;p&gt;Vegard: /* Games */ Red Dead Redemption 2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is a list of &amp;quot;frame analysis&amp;quot; blog posts, i.e. posts which dissect how a game does its rendering.&lt;br /&gt;
&lt;br /&gt;
== Engines ==&lt;br /&gt;
&lt;br /&gt;
=== AnKi 3D ===&lt;br /&gt;
&lt;br /&gt;
* http://anki3d.org/anatomy-of-a-frame-in-anki/&lt;br /&gt;
&lt;br /&gt;
== Games ==&lt;br /&gt;
&lt;br /&gt;
=== A Plague Tale: Innocence ===&lt;br /&gt;
&lt;br /&gt;
* https://gamingbolt.com/a-plague-tale-innocence-graphics-analysis-one-of-the-best-looking-games-of-this-gen&lt;br /&gt;
&lt;br /&gt;
=== Batman: Arkham Knight ===&lt;br /&gt;
&lt;br /&gt;
* http://morad.in/2020/04/03/unmasking-arkham-knight/&lt;br /&gt;
&lt;br /&gt;
=== Battlefield 3 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.slideshare.net/DICEStudio/directx-11-rendering-in-battlefield-3&lt;br /&gt;
&lt;br /&gt;
=== Battlefield 4 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.slideshare.net/DevCentralAMD/rendering-battlefield-4-with-mantle-yuriy-o-donnell&lt;br /&gt;
&lt;br /&gt;
=== BioShock Infinite ===&lt;br /&gt;
&lt;br /&gt;
* https://solid-angle.blogspot.com/2014/03/bioshock-infinite-lighting.html&lt;br /&gt;
&lt;br /&gt;
=== Castlevania: Lords of Shadow 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.elopezr.com/castlevania-lords-of-shadow-2-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Deus Ex: Human Revolution ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/03/10/deus-ex-human-revolution-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Doom 2016 ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2016/09/09/doom-2016-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Far Cry 5 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.gdcvault.com/play/1025480/Terrain-Rendering-in-Far-Cry&lt;br /&gt;
&lt;br /&gt;
=== Gears of War 5 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.eurogamer.net/articles/digitalfoundry-2019-gears-5-tech-interview&lt;br /&gt;
&lt;br /&gt;
=== GTA V ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/11/02/gta-v-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Killzone 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://www.guerrilla-games.com/read/deferred-rendering-in-killzone-2&lt;br /&gt;
&lt;br /&gt;
=== League of Legends ===&lt;br /&gt;
&lt;br /&gt;
* https://technology.riotgames.com/news/trip-down-lol-graphics-pipeline&lt;br /&gt;
&lt;br /&gt;
=== Metal Gear Solid V ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2017/12/15/mgs-v-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== Metro Exodus ===&lt;br /&gt;
&lt;br /&gt;
* https://aschrein.github.io/2019/08/11/metro_breakdown.html&lt;br /&gt;
&lt;br /&gt;
=== Middle Earth: Shadow of Mordor ===&lt;br /&gt;
&lt;br /&gt;
* http://www.elopezr.com/the-rendering-of-middle-earth-shadow-of-mordor/&lt;br /&gt;
&lt;br /&gt;
=== Ni No Kuni 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.thomaspoulet.fr/ninokuni2-frame/&lt;br /&gt;
&lt;br /&gt;
=== Red Dead Redemption 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://imgeself.github.io/posts/2020-06-19-graphics-study-rdr2/&lt;br /&gt;
&lt;br /&gt;
=== Resident Evil 2 ===&lt;br /&gt;
&lt;br /&gt;
* https://aschrein.github.io/2019/08/01/re2_breakdown.html&lt;br /&gt;
&lt;br /&gt;
=== Rise of the Tomb Raider ===&lt;br /&gt;
&lt;br /&gt;
* http://www.elopezr.com/the-rendering-of-rise-of-the-tomb-raider/&lt;br /&gt;
&lt;br /&gt;
=== Supreme Commander ===&lt;br /&gt;
&lt;br /&gt;
* http://www.adriancourreges.com/blog/2015/06/23/supreme-commander-graphics-study/&lt;br /&gt;
&lt;br /&gt;
=== The Witcher 3 ===&lt;br /&gt;
&lt;br /&gt;
* https://astralcode.blogspot.com/2018/11/reverse-engineering-rendering-of.html&lt;br /&gt;
&lt;br /&gt;
=== The Witness ===&lt;br /&gt;
&lt;br /&gt;
* https://blog.thomaspoulet.fr/the-witness-frame-part-1/&lt;br /&gt;
* https://blog.thomaspoulet.fr/the-witness-frame-part-2/&lt;br /&gt;
&lt;br /&gt;
=== Total War ===&lt;br /&gt;
&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-2/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-3/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-4/&lt;br /&gt;
* https://gpuopen.com/anatomy-total-war-engine-part-5/&lt;br /&gt;
&lt;br /&gt;
=== Wind Waker ===&lt;br /&gt;
&lt;br /&gt;
* https://polycount.com/discussion/104415/zelda-wind-waker-tech-and-texture-analysis-picture-heavy&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Sphere_tesselation&amp;diff=304</id>
		<title>Sphere tesselation</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Sphere_tesselation&amp;diff=304"/>
		<updated>2020-06-16T10:41:34Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* https://stackoverflow.com/a/7687312&lt;br /&gt;
* https://medium.com/game-dev-daily/four-ways-to-create-a-mesh-for-a-sphere-d7956b825db4&lt;br /&gt;
* https://scitepress.org/papers/2007/20747/20747.pdf&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Self-running_source&amp;diff=303</id>
		<title>Self-running source</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Self-running_source&amp;diff=303"/>
		<updated>2020-05-25T11:24:32Z</updated>

		<summary type="html">&lt;p&gt;Vegard: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== C ==&lt;br /&gt;
&lt;br /&gt;
Set the executable bit on the following polyglot C/shell source file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;C&amp;quot;&amp;gt;&lt;br /&gt;
#if 0&lt;br /&gt;
gcc -Wall $0 &amp;amp;&amp;amp; exec ./a.out; exit 1&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char *argv[])&lt;br /&gt;
{&lt;br /&gt;
        printf(&amp;quot;Hello world!\n&amp;quot;);&lt;br /&gt;
        return 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is my favourite version because:&lt;br /&gt;
* readable (e.g. no multiline comments)&lt;br /&gt;
* minimal boilerplate&lt;br /&gt;
* only runs the program if it compiled successfully&lt;br /&gt;
* exits with 1 if there was an error&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* https://coderwall.com/p/e1htcg/self-compiling-source-code&lt;br /&gt;
* https://twitter.com/dannas_/status/1238066416286400512&lt;br /&gt;
* https://twitter.com/_monoid/status/1264858552440586248&lt;br /&gt;
&lt;br /&gt;
[[Category:C]]&lt;br /&gt;
[[Category:Programming]]&lt;br /&gt;
[[Category:C preprocessor snippets]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Regex_syntax&amp;diff=302</id>
		<title>Regex syntax</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Regex_syntax&amp;diff=302"/>
		<updated>2020-05-20T08:14:56Z</updated>

		<summary type="html">&lt;p&gt;Vegard: fix bug&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
I can never remember which programs use which regex variants, so here&#039;s a quick recap sheet.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
! grep (GNU)&lt;br /&gt;
! sed (GNU)&lt;br /&gt;
! vim&lt;br /&gt;
! less (GNU)&lt;br /&gt;
! python&lt;br /&gt;
|+&lt;br /&gt;
| capture&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| option&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| word boundary&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\b&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or one&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or more&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or more (non-greedy)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;tt&amp;gt;\{-}&amp;lt;/tt&amp;gt;&lt;br /&gt;
| (unknown)&lt;br /&gt;
| &amp;lt;tt&amp;gt;*?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| one or more&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| one or more (non-greedy)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;tt&amp;gt;\{-1,}&amp;lt;/tt&amp;gt;&lt;br /&gt;
| (unknown)&lt;br /&gt;
| &amp;lt;tt&amp;gt;+?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* https://www.gnu.org/software/grep/manual/html_node/Regular-Expressions.html&lt;br /&gt;
* http://vimregex.com/&lt;br /&gt;
* https://docs.python.org/3/library/re.html&lt;br /&gt;
&lt;br /&gt;
[[Category:Programming]]&lt;br /&gt;
[[Category:Cheat sheets]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Regex_syntax&amp;diff=301</id>
		<title>Regex syntax</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Regex_syntax&amp;diff=301"/>
		<updated>2020-05-20T08:00:22Z</updated>

		<summary type="html">&lt;p&gt;Vegard: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
I can never remember which programs use which regex variants, so here&#039;s a quick recap sheet.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
! grep (GNU)&lt;br /&gt;
! sed (GNU)&lt;br /&gt;
! vim&lt;br /&gt;
! less (GNU)&lt;br /&gt;
! python&lt;br /&gt;
|+&lt;br /&gt;
| capture&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| option&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| word boundary&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\b&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or one&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or more&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or more (non-greedy)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;tt&amp;gt;\{-}&amp;lt;/tt&amp;gt;&lt;br /&gt;
| (unknown)&lt;br /&gt;
| &amp;lt;tt&amp;gt;*?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| one or more&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| one or more (non-greedy)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;tt&amp;gt;\{-1,}&amp;lt;/tt&amp;gt;&lt;br /&gt;
| (unknown)&lt;br /&gt;
| &amp;lt;tt&amp;gt;+?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* https://www.gnu.org/software/grep/manual/html_node/Regular-Expressions.html&lt;br /&gt;
* http://vimregex.com/&lt;br /&gt;
* https://docs.python.org/3/library/re.html&lt;br /&gt;
&lt;br /&gt;
[[Category:Programming]]&lt;br /&gt;
[[Category:Cheat sheets]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Regex_syntax&amp;diff=300</id>
		<title>Regex syntax</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Regex_syntax&amp;diff=300"/>
		<updated>2020-05-20T07:59:55Z</updated>

		<summary type="html">&lt;p&gt;Vegard: less&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
I can never remember which programs use which regex variants, so here&#039;s a quick recap sheet.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!&lt;br /&gt;
! grep (GNU)&lt;br /&gt;
! sed (GNU)&lt;br /&gt;
! vim&lt;br /&gt;
! less&lt;br /&gt;
! python&lt;br /&gt;
|+&lt;br /&gt;
| capture&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;\)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;(&amp;lt;/tt&amp;gt; ... &amp;lt;tt&amp;gt;)&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| option&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;\|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;|&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| word boundary&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\&amp;lt;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;\&amp;gt;&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\b&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or one&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;?&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or more&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;*&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| zero or more (non-greedy)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;tt&amp;gt;\{-}&amp;lt;/tt&amp;gt;&lt;br /&gt;
| (unknown)&lt;br /&gt;
| &amp;lt;tt&amp;gt;*?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| one or more&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;\+&amp;lt;/tt&amp;gt;&lt;br /&gt;
| &amp;lt;tt&amp;gt;+&amp;lt;/tt&amp;gt;&lt;br /&gt;
|+&lt;br /&gt;
| one or more (non-greedy)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &amp;lt;tt&amp;gt;\{-1,}&amp;lt;/tt&amp;gt;&lt;br /&gt;
| (unknown)&lt;br /&gt;
| &amp;lt;tt&amp;gt;+?&amp;lt;/tt&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== References ==&lt;br /&gt;
&lt;br /&gt;
* https://www.gnu.org/software/grep/manual/html_node/Regular-Expressions.html&lt;br /&gt;
* http://vimregex.com/&lt;br /&gt;
* https://docs.python.org/3/library/re.html&lt;br /&gt;
&lt;br /&gt;
[[Category:Programming]]&lt;br /&gt;
[[Category:Cheat sheets]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Mesh_simplification&amp;diff=299</id>
		<title>Mesh simplification</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Mesh_simplification&amp;diff=299"/>
		<updated>2020-05-16T06:14:53Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
See:&lt;br /&gt;
* https://github.com/zeux/meshoptimizer&lt;br /&gt;
* https://github.com/dougbinks/BunnyLOD&lt;br /&gt;
&lt;br /&gt;
[[Category:Graphics programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=Buffer-centric_IO&amp;diff=298</id>
		<title>Buffer-centric IO</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=Buffer-centric_IO&amp;diff=298"/>
		<updated>2020-05-13T09:45:30Z</updated>

		<summary type="html">&lt;p&gt;Vegard: new page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Stub}}&lt;br /&gt;
&lt;br /&gt;
See: https://fgiesen.wordpress.com/2011/11/21/buffer-centric-io/&lt;br /&gt;
&lt;br /&gt;
[[Category:Programming]]&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
	<entry>
		<id>http://vegard.wiki/mediawiki/index.php?title=MediaWiki:Copyright&amp;diff=297</id>
		<title>MediaWiki:Copyright</title>
		<link rel="alternate" type="text/html" href="http://vegard.wiki/mediawiki/index.php?title=MediaWiki:Copyright&amp;diff=297"/>
		<updated>2020-05-02T21:19:35Z</updated>

		<summary type="html">&lt;p&gt;Vegard: update year&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;All pages &amp;amp;copy; Copyright 2019-2020 &amp;amp;mdash; Vegard Nossum, unless otherwise noted.&lt;/div&gt;</summary>
		<author><name>Vegard</name></author>
	</entry>
</feed>