@@ -5,11 +5,11 @@ import { mat4_mul, mat4_perspective, mat4_translate_z, quat_identity, quat_from_
import { create _program , make _buffer } from './gl_utils.mjs' ;
import { PAINT _BG , PAINT _BG _PBR , PAINT _BG _NOISE , Paint _State } from './paint_state.mjs' ;
import { Spin _State } from './spin_state.mjs' ;
import { shape _distortion , build _triangle _geo , build _ goldberg _geo } from './render_geo.mjs' ;
import { shape _distortion , build _goldberg _geo } from './render_geo.mjs' ;
import { build _goldberg _adjacency } from './topology.mjs' ;
import { Undo _State } from './undo_state.mjs' ;
import { Env _State } from './env_state.mjs' ;
import { PALETTES , DEFAULT_PALETTE } from './palettes.mjs' ;
import { DEFAULT _PALETTE } from './palettes.mjs' ;
// ---------------------------------------------------------------------------
// Load shaders
@@ -32,7 +32,6 @@ const paint = new Paint_State();
const undo _state = new Undo _State ( ) ;
const env = new Env _State ( ) ;
let current _geo = null ;
let current _stage = 'relaxed' ;
let current _palette = DEFAULT _PALETTE ;
let building = false ;
let active _brush _side = 'left' ;
@@ -42,12 +41,7 @@ let paint_dirty = false;
let debounce _timer = null ;
function get _params ( ) {
return {
depth : parseInt ( document . getElementById ( 'depth' ) . value , 10 ) ,
iters : parseInt ( document . getElementById ( 'iters' ) . value , 10 ) ,
alpha _edge : parseFloat ( document . getElementById ( 'alpha-edge' ) . value ) ,
alpha _centroid : parseFloat ( document . getElementById ( 'alpha-centroid' ) . value ) ,
} ;
return { depth : 5 , iters : 500 , alpha _edge : 0 , alpha _centroid : 0.04 } ;
}
@@ -106,7 +100,7 @@ function upload_geo() {
function rebuild _face _colors ( ) {
if ( ! cache . goldberg || ! face _col _buf ) { return ; }
const goldberg = cache . goldberg ;
const use _relaxed = current _stage === 'relaxed' ;
const use _relaxed = true ;
const fcol = [ ] , fpbr = [ ] , fnoise = [ ] ;
for ( let fi = 0 ; fi < goldberg . faces . length ; fi ++ ) {
const face = goldberg . faces [ fi ] ;
@@ -202,8 +196,6 @@ function apply_history(side) {
async function build ( ) {
if ( building ) { return ; }
building = true ;
const btn = document . getElementById ( 'build-btn' ) ;
btn . disabled = true ;
const p = get _params ( ) ;
const t0 = Date . now ( ) ;
@@ -217,14 +209,6 @@ async function build() {
cache . poly = null ;
cache . goldberg = null ;
}
if ( current _stage === 'ico' ) {
current _geo = build _triangle _geo ( cache . ico , current _palette ) ;
upload _geo ( ) ;
cache . depth = p . depth ;
set _stats ( current _geo , 'Icosahedron' , Date . now ( ) - t0 ) ;
set _status ( '' ) ;
return ;
}
if ( depth _changed || ! cache . poly ) {
let poly = cache . ico ;
@@ -235,14 +219,6 @@ async function build() {
cache . poly = poly ;
cache . goldberg = null ;
}
if ( current _stage === 'subdiv' ) {
current _geo = build _triangle _geo ( cache . poly , current _palette ) ;
upload _geo ( ) ;
cache . depth = p . depth ;
set _stats ( current _geo , ` Subdivided × ${ p . depth } ` , Date . now ( ) - t0 ) ;
set _status ( '' ) ;
return ;
}
if ( depth _changed || ! cache . goldberg ) {
set _status ( 'Building Goldberg dual…' ) ; await yield _ui ( 30 ) ;
@@ -250,16 +226,8 @@ async function build() {
cache . adj = null ;
undo _state . invalidate ( ) ;
}
if ( current _stage === 'goldberg' ) {
current _geo = build _goldberg _geo ( cache . goldberg , false , paint , current _palette ) ;
upload _geo ( ) ;
cache . depth = p . depth ;
set _stats ( current _geo , 'Goldberg (no relax)' , Date . now ( ) - t0 ) ;
set _status ( '' ) ;
return ;
}
set _status ( ` Relaxing ( ${ p . iters } iters, edge= ${ p . alpha _edge } , centroid= ${ p . alpha _centroid } )… ` ) ;
set _status ( ` Relaxing ( ${ p . iters } iters)… ` ) ;
await yield _ui ( 50 ) ;
cache . goldberg . relax _sphere ( p . iters , p . alpha _edge , p . alpha _centroid ) ;
current _geo = build _goldberg _geo ( cache . goldberg , true , paint , current _palette ) ;
@@ -270,7 +238,6 @@ async function build() {
} finally {
building = false ;
btn . disabled = false ;
snapshot _now ( ) ;
}
}
@@ -302,7 +269,7 @@ function pick_face(px, py) {
const hx = ro [ 0 ] + t * rd [ 0 ] , hy = ro [ 1 ] + t * rd [ 1 ] , hz = ro [ 2 ] + t * rd [ 2 ] ;
const goldberg = cache . goldberg ;
const use _relaxed = current _stage === 'relaxed' ;
const use _relaxed = true ;
let best _fi = - 1 , best _dot = - Infinity ;
for ( let fi = 0 ; fi < goldberg . faces . length ; fi ++ ) {
const face = goldberg . faces [ fi ] ;
@@ -409,7 +376,7 @@ function faces_at_radius(center_fi, radius) {
// ---------------------------------------------------------------------------
function save _paint ( ) {
const depth = parseInt ( document . getElementById ( 'depth' ) . value ) ;
const depth = 5 ;
const faces = [ ] ;
for ( const [ fi , c ] of paint . face _colors ) {
const h = v => Math . round ( v * 255 ) . toString ( 16 ) . padStart ( 2 , '0' ) ;
@@ -432,10 +399,7 @@ function load_paint(file) {
reader . onload = e => {
try {
const data = JSON . parse ( e . target . result ) ;
const depth = parseInt ( document . getElementById ( 'depth' ) . value ) ;
if ( data . depth !== depth ) {
document . getElementById ( 'depth' ) . value = data . depth ;
document . getElementById ( 'depth-val' ) . textContent = data . depth ;
if ( data . depth !== 5 ) {
cache . poly = null ; cache . goldberg = null ; cache . adj = null ;
}
paint . face _colors . clear ( ) ;
@@ -730,50 +694,6 @@ function render_frame(ts) {
// UI wiring
// ---------------------------------------------------------------------------
// Palette buttons (built dynamically from PALETTES array).
{
const grid = document . getElementById ( 'palette-grid' ) ;
for ( const p of PALETTES ) {
const btn = document . createElement ( 'button' ) ;
btn . className = 'sb' + ( p === DEFAULT _PALETTE ? ' active' : '' ) ;
btn . textContent = p . name ;
btn . addEventListener ( 'click' , ( ) => {
current _palette = p ;
grid . querySelectorAll ( '.sb' ) . forEach ( b => b . classList . remove ( 'active' ) ) ;
btn . classList . add ( 'active' ) ;
rebuild _face _colors ( ) ;
// Triangle stages need a full rebuild since positions are shared.
if ( current _stage === 'ico' || current _stage === 'subdiv' ) { build ( ) ; }
} ) ;
grid . appendChild ( btn ) ;
}
}
document . querySelectorAll ( '.sb' ) . forEach ( btn => {
btn . addEventListener ( 'click' , ( ) => {
document . querySelectorAll ( '.sb' ) . forEach ( b => b . classList . remove ( 'active' ) ) ;
btn . classList . add ( 'active' ) ;
current _stage = btn . dataset . stage ;
build ( ) ;
} ) ;
} ) ;
document . getElementById ( 'depth' ) . addEventListener ( 'input' , ( ) => {
const d = parseInt ( document . getElementById ( 'depth' ) . value ) ;
document . getElementById ( 'depth-val' ) . textContent = d ;
document . getElementById ( 'iters' ) . value = d * 8 ;
cache . poly = null ;
cache . goldberg = null ;
cache . adj = null ;
} ) ;
document . getElementById ( 'build-btn' ) . addEventListener ( 'click' , ( ) => {
if ( current _stage === 'relaxed' ) {
cache . goldberg = null ;
cache . adj = null ;
}
build ( ) ;
} ) ;
document . getElementById ( 'spin-btn' ) . addEventListener ( 'click' , ( ) => {
@@ -802,12 +722,8 @@ const update_paint_buttons = () => {
} ;
const make _tool _handler = tool => ( ) => {
if ( ! paint . enabled || paint . tool !== tool ) {
paint . enabled = true ;
paint . tool = tool ;
} else {
paint . enabled = false ;
}
paint . enabled = true ;
paint . tool = tool ;
update _paint _buttons ( ) ;
} ;