import echo::{Context, Cell, contain};
import lygia::sdf::boxSDF::boxSDF1;
fn sdf(p: vec3f, ctx: Context) -> f32 {
let radius = 0.75;
let offset = vec3f(1, 0.5, 0);
var d0 = length(p + offset) - radius;
var d1 = boxSDF1(p - offset, vec3(radius));
return min(d0, d1);
}
fn map_cell(i: Cell, ctx: Context) -> Cell {
var p = contain(i.sp, ctx.resolution);
var o = i;
var ro = vec3f(0);
var rd = vec3f(0);
let height = 1f;
let distance = 4f;
camera(ctx.time, height, distance, p, &ro, &rd);
let sdf_precision = 0.01;
let sdf_far = 20.0;
var t = 0f;
for (var i: i32 = 0; i < 50; i++) {
let d = sdf(ro + rd * t, ctx);
if (d < sdf_precision || t > sdf_far) { break; }
t += d;
}
if (t <= sdf_far) {
let normal = calc_normal(ro + rd * t, ctx);
o.fg = abs(normal);
o.ch = 48;
}
return echo::map_cell_selection(o, i, ctx);
}
fn lookAt(camera: vec3f, center: vec3f, roll: f32) -> mat3x3f {
let r = vec3(sin(roll), cos(roll), 0);
let w = normalize(center - camera);
let u = normalize(cross(w, r));
let v = normalize(cross(u, w));
return mat3x3(u, v, w);
}
fn camera(
angle: f32,
height: f32,
distance: f32,
coord: vec2f,
ro: ptr<function, vec3f>,
rd: ptr<function, vec3f>
) {
*ro = vec3f(
distance * sin(angle),
height,
distance * cos(angle),
);
let view = lookAt(*ro, vec3(0), 0.0);
*rd = normalize(view * vec3(coord, 2.0));
}
const epsilon: f32 = 0.002;
const v1 = vec3f( 1.0,-1.0,-1.0);
const v2 = vec3f(-1.0,-1.0, 1.0);
const v3 = vec3f(-1.0, 1.0,-1.0);
const v4 = vec3f( 1.0, 1.0, 1.0);
fn calc_normal(pos: vec3f, ctx: Context) -> vec3f {
return normalize(
v1 * sdf(pos + v1 * epsilon, ctx) +
v2 * sdf(pos + v2 * epsilon, ctx) +
v3 * sdf(pos + v3 * epsilon, ctx) +
v4 * sdf(pos + v4 * epsilon, ctx)
);
}