import { PAINT_BG, PAINT_BG_PBR, PAINT_BG_NOISE } from './paint_state.mjs'; export function desaturate(c, s) { const lum = 0.299*c[0] + 0.587*c[1] + 0.114*c[2]; return [lum + (c[0]-lum)*s, lum + (c[1]-lum)*s, lum + (c[2]-lum)*s]; } export function distortion_color(ratio) { const t = Math.min(Math.max((ratio - 1) / 0.4, 0), 1); return desaturate([Math.min(1, 2*t), t < 0.5 ? t*1.4 : 0.7-(t-0.5)*1.4, Math.max(0, 1-2*t)], 0.45); } export function shape_distortion(verts) { const n = verts.length; let cx=0, cy=0, cz=0; for (const v of verts) { cx+=v.x; cy+=v.y; cz+=v.z; } cx/=n; cy/=n; cz/=n; let mn=Infinity, mx=0; for (const v of verts) { const d = Math.sqrt((v.x-cx)**2+(v.y-cy)**2+(v.z-cz)**2); if (d < mn) { mn=d; } if (d > mx) { mx=d; } } return mn > 1e-12 ? mx/mn : 1; } // Triangle mesh (icosahedron / subdivided). export function build_triangle_geo(poly, palette) { const fpos=[], fcol=[], fpbr=[], fnoise=[], epos=[]; let worst_shape = 0; for (const face of poly.faces) { const v = face.vertices.map(vi => poly.vertices[vi].to_vec3()); const e1x=v[1].x-v[0].x, e1y=v[1].y-v[0].y, e1z=v[1].z-v[0].z; const e2x=v[2].x-v[0].x, e2y=v[2].y-v[0].y, e2z=v[2].z-v[0].z; const nx=e1y*e2z-e1z*e2y, ny=e1z*e2x-e1x*e2z, nz=e1x*e2y-e1y*e2x; const cx=(v[0].x+v[1].x+v[2].x)/3, cy=(v[0].y+v[1].y+v[2].y)/3, cz=(v[0].z+v[1].z+v[2].z)/3; if (nx*cx + ny*cy + nz*cz < 0) { [v[1], v[2]] = [v[2], v[1]]; } let mn=Infinity, mx=0; for (let i=0; i<3; i++) { const a=v[i], b=v[(i+1)%3]; const l=Math.sqrt((b.x-a.x)**2+(b.y-a.y)**2+(b.z-a.z)**2); if (lmx) { mx=l; } } const ratio = mn>1e-12 ? mx/mn : 1; if (ratio > worst_shape) { worst_shape = ratio; } const c = palette.face_color(ratio, false); for (const vert of v) { fpos.push(vert.x,vert.y,vert.z); fcol.push(c[0],c[1],c[2]); fpbr.push(0.0,0.6); fnoise.push(...PAINT_BG_NOISE); } for (let i=0; i<3; i++) { const a=v[i], b=v[(i+1)%3]; epos.push(a.x,a.y,a.z, b.x,b.y,b.z); } } return { face_pos: new Float32Array(fpos), face_col: new Float32Array(fcol), face_pbr: new Float32Array(fpbr), face_noise: new Float32Array(fnoise), face_verts: fpos.length/3, edge_pos: new Float32Array(epos), edge_verts: epos.length/3, stats: { faces: poly.faces.length, vertices: poly.vertices.length, worst_shape }, }; } // Goldberg polygonal mesh. paint is a Paint_State (or null for non-paint mode). export function build_goldberg_geo(goldberg, use_relaxed, paint, palette) { const fpos=[], fcol=[], fpbr=[], fnoise=[], epos=[]; let worst_shape = 0; for (let fi=0; fi worst_shape) { worst_shape = sr; } let c, pbr, noise; if (paint?.enabled) { const in_preview = paint.preview?.faces.has(fi); c = in_preview ? paint.preview.color : (paint.face_colors.get(fi) ?? PAINT_BG); pbr = in_preview ? (paint.preview.pbr ?? PAINT_BG_PBR) : (paint.face_pbr.get(fi) ?? PAINT_BG_PBR); noise = in_preview ? (paint.preview.noise ?? PAINT_BG_NOISE) : (paint.face_noise.get(fi) ?? PAINT_BG_NOISE); } else { c = palette.face_color(sr, face.is_pentagon); pbr = [0.0, 0.6]; noise = PAINT_BG_NOISE; } for (let i=1; if.is_pentagon).length, worst_shape, }, }; }