rusterix 0.8.100

Rusterix is the game engine of Eldiron.
Documentation

// Value noise, based on https://www.shadertoy.com/view/4dS3Wd
// By Morgan McGuire @morgan3d, http://graphicscodex.com
// Reuse permitted under the BSD license.

fn value_hash(p, scale) {
    p = mod(p, scale);
    let p3 = fract(p.xyx * 0.13); 
    p3 += dot(p3, p3.yzx + 3.333); 
    return fract((p3.x + p3.y) * p3.z); 
}

fn value_noise(x, scale) {
    x *= scale;

    let i = floor(x);
    let f = fract(x);

	let a = value_hash(i, scale);
    let b = value_hash(i + vec2(1.0, 0.0), scale);
    let c = value_hash(i + vec2(0.0, 1.0), scale);
    let d = value_hash(i + vec2(1.0, 1.0), scale);

    let u = f * f * (3.0 - 2.0 * f);
	return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

fn fbm_value(x, scale) {
	let v = 0.0;
	let a = 0.5;
	let shift = vec2(100);
	for (let i = 0; i < 5; i += 1) {
		v += a * value_noise(x, scale);
        x = rotate2d(x, 0.5) * 2.0 + shift;
		a *= 0.5;
	}
	return v;
}

fn make_value_noise() {
    color = value_noise(uv, 20);
}

fn make_fbm_value_noise() {
    color = fbm_value(uv, 20);
}

let tex = alloc(512, 512);
iterate(tex, "make_value_noise");
save(tex, "rusteria/embedded/value.png");

iterate(tex, "make_fbm_value_noise");
save(tex, "rusteria/embedded/fbm_value.png");

/*
// Simplex noise, based on https://www.shadertoy.com/view/Msf3WH
// The MIT License
// Copyright © 2013 Inigo Quilez

fn simplex_hash( p, scale )
{
    //p = mod(p, scale);
	p = vec2( dot2(p,vec2(127.1,311.7)), dot2(p,vec2(269.5,183.3)) );
    let t = -1.0 + 2.0*fract(sin2(p)*43758.5453123);
    return vec3(t.x, t.y, 0.0);
}

fn simplex_noise( p, scale )
{
    //p *= scale;

    let K1 = 0.366025404; // (sqrt(3)-1)/2;
    let K2 = 0.211324865; // (3-sqrt(3))/6;

	let  i = floor( p + (p.x+p.y)*K1 );
    let  a = p - i + (i.x+i.y)*K2;
    let m = step(a.y,a.x); 
    let  o = vec2(m,1.0-m);
    let  b = a - o + K2;
	let  c = a - 1.0 + 2.0*K2;
    let  h = max( 0.5-vec3(dot2(a,a), dot2(b,b), dot2(c,c) ), 0.0 );
	let  n = h*h*h*h*vec3( dot2(a,simplex_hash(i+0.0, scale)), dot2(b,simplex_hash(i+o, scale)), dot2(c,simplex_hash(i+1.0, scale)));
    return 0.5 + dot( n, vec3(70.0) ) * 0.5;
}

fn make_simplex_noise() {
    color = simplex_noise(uv * 10.0, 1.0);
}

iterate(tex, "make_simplex_noise");
save(tex, "rusteria/embedded/simplex.png");
*/

// True 2D Perlin gradient noise

// Gradient hash: pick one of 8 unit vectors based on lattice index
fn grad2(i) {
    // Hash into [0,8)
    let h = floor(fract(sin2(dot2(i, vec2(127.1, 311.7))) * 43758.5453) * 8.0);

    // Branch by range, since h is float
    if (h < 1.0) { return vec3( 1.0,  0.0, 0.0); }
    if (h < 2.0) { return vec3(-1.0,  0.0, 0.0); }
    if (h < 3.0) { return vec3( 0.0,  1.0, 0.0); }
    if (h < 4.0) { return vec3( 0.0, -1.0, 0.0); }
    if (h < 5.0) { return vec3( 0.707,  0.707, 0.0); }
    if (h < 6.0) { return vec3(-0.707,  0.707, 0.0); }
    if (h < 7.0) { return vec3( 0.707, -0.707, 0.0); }
    return vec3(-0.707, -0.707, 0.0);
}

// Fade curve (Perlin's improved smoothstep)
fn fade(t) {
    return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}

fn perlin_noise(p, period) {
    p *= period;

    let i = floor(p);
    let f = fract(p);

    // wrap lattice indices to [0, period)
    let iw   = mod(i, period);
    let iw10 = mod(i + vec2(1.0, 0.0), period);
    let iw01 = mod(i + vec2(0.0, 1.0), period);
    let iw11 = mod(i + vec2(1.0, 1.0), period);

    // Gradient vectors at four wrapped corners
    let g00 = grad2(iw);
    let g10 = grad2(iw10);
    let g01 = grad2(iw01);
    let g11 = grad2(iw11);

    // Offsets from *unwrapped* corners (to preserve local geometry)
    let d00 = vec2(f.x,   f.y);
    let d10 = vec2(f.x-1, f.y);
    let d01 = vec2(f.x,   f.y-1);
    let d11 = vec2(f.x-1, f.y-1);

    // Dot products
    let v00 = dot2(d00, g00);
    let v10 = dot2(d10, g10);
    let v01 = dot2(d01, g01);
    let v11 = dot2(d11, g11);

    // Fade
    let u = fade(f);

    // Interpolation
    let nx0 = mix(v00, v10, u.x);
    let nx1 = mix(v01, v11, u.x);
    let nxy = mix(nx0, nx1, u.y);

    return 0.5 * vec3(nxy + 1.0);
}

fn perlin_fbm(p, scale) {
    let v = 0.0;
    let a = 0.5;
    for (let i = 0; i < 5; i += 1) {
        v += a * perlin_noise(p, scale);
        p = p * 2.0 + vec2(100.0);
        a *= 0.5;
    }
    return vec3(v);
}

fn make_perlin_noise() {
    color = perlin_noise(uv, 10.0);
}

fn make_perlin_fbm() {
    color = perlin_fbm(uv, 10.0);
}

iterate(tex, "make_perlin_noise");
save(tex, "rusteria/embedded/perlin.png");

iterate(tex, "make_perlin_fbm");
save(tex, "rusteria/embedded/fbm_perlin.png");

// Bricks

fn hash21(p)
{
	let p3 = fract(p * vec3(.1031, .1030, .0973));
	p3 += dot(p3, p3.yzx + 33.33);
    return fract((p3.xx+p3.yz)*p3.zy);
}

fn make_bricks() {
    let ratio = 3.0;
    let cell = 18.0;
    let gap  = 0.05;
    let bevel = 0.0;
    let cycle = vec2( round(cell / ratio), cell);

    let u = uv;

    let w = vec2(ratio, 1.0);
    u *= cell / w;

    u.x += 0.5 * (floor(u.y) % 2.0);

    let p = u % cycle;
    p = floor(p);
    p.z = 0.0;
    let id = hash21(p);

    let s = w* (fract(u) - 1./2.); 

    let a = w/2. - gap - abs(s);
    let b  = a * 2. / bevel;
    let m = min(b.x,b.y); 

    let mask = clamp( m ,0.,1.); 

    color = vec2(mask.x, id.x);
}

iterate(tex, "make_bricks");
save(tex, "rusteria/embedded/bricks.png");

// Tiles

fn make_tiles() {
    let ratio = 1.0;
    let cell = 18.0;
    let gap  = 0.01;
    let bevel = 0.1;
    let cycle = vec2( ceil(cell / ratio), cell);

    let u = uv;

    let w = vec2(ratio, 1.0);
    u *= cell / w;

    //u.x += 0.5 * (floor(u.y) % 2.0);

    let p = mod(u, cycle);
    p = floor(p);
    p.z = 0.0;
    let id = hash21(p);

    let s = w* (fract(u) - 1./2.); 

    let a = w/2. - gap - abs(s);
    let b  = a * 2. / bevel;
    let m = min(b.x,b.y); 

    let mask = clamp( m ,0.,1.); 

    color = vec2(mask.x, id.x);
}

iterate(tex, "make_tiles");
save(tex, "rusteria/embedded/tiles.png");

// Shanes subdivided blocks

fn s_box(p, b, rf) {
    let q = abs(p) - b + rf;
    return length(max(q, 0.0)) + min(max(q.x, q.y), 0.0) - rf;
}

fn make_blocks() {

    let gap = 0.1;
    let rotation = 2;
    let rounding = 0.04;

    let p = uv;
    let ip = floor(uv);
    p -= ip;

    let last_l = 0.0;
    let l = vec2(1.0, 1.0);
    let r = hash21(ip);

    for (let i = 0; i < 6; i += 1) {
        r = fract(dot(l + r, vec2(123.71, 439.43))) * 0.4 + (1.0 - 0.4) / 2.0;

        last_l = l;
        if l.x > l.y {
            p = vec2(p.y, p.x);
            l = vec2(l.y, l.x);
        }

        if p.x < r {
            l.x /= r;
            p.x /= r;
        } else {
            l.x /= 1.0 - r;
            p.x = (p.x - r) / (1.0 - r);
        }

        if last_l.x > last_l.y {
            p = vec2(p.y, p.x);
            l = vec2(l.y, l.x);
        }
    }
    p -= 0.5;

    // Create the id
    let id = hash21(ip + l);

    // Slightly rotate the tile based on its id
    p = rotate2d(p, (id - 0.5) * rotation);

    // Gap, or mortar, width. Using "l" to keep it roughly constant.
    let th = l * 0.02 * gap;

    // Take the subdivided space and turn them into rounded pavers.
    let c = s_box(p, 0.5 - th, rounding);

    let c01 = clamp(0.5 - c / (2.0 * 0.5), 0.0, 1.0);

    let mask = 1.0;
    if c > 0.0 {
        mask = 0.0;
    }
    color = vec3(mask.x, id.x, c01.x);
}

iterate(tex, "make_blocks");
save(tex, "rusteria/embedded/blocks.png");