@@ -32,14 +32,6 @@ const MAX_QUEUE_SIZE = 1e6
3232const MIN_PATTERN_SIZE = 0.0005 // ignore patterns where either side is smaller than this
3333const DEBUG = true as boolean
3434
35- // -- hacky global state
36-
37- type GlobalMutableState = {
38- drawScreenCalls : number
39- maxQueueSize : number
40- queueIterations : number
41- }
42-
4335// -- helper functions
4436
4537const mapPatternToViewportSpace = ( pattern : AbsolutePattern , screenSize : Size ) : ViewportPattern => ( {
@@ -122,79 +114,92 @@ type QueueEntry = {
122114 depth : number
123115}
124116
125- const draw = (
126- ctx : CanvasRenderingContext2D ,
127- state : State ,
128- globalMutableState : GlobalMutableState ,
129- queue : Queue < QueueEntry >
130- ) : void => {
131- const screenSize = getScreenSize ( ctx )
117+ function * generateDrawQueue ( state : State ) : Generator < QueueEntry , void , void > {
118+ console . log (
119+ `generateDrawQueue start. Initial screens: ${ state . screens . length } , Patterns: ${ state . patterns . length } `
120+ )
132121
133- // Shared styles.
134- ctx . fillStyle = 'black'
135- ctx . lineWidth = 1
122+ const patternQueue = new Queue < QueueEntry > (
123+ state . screens . map ( screen => ( {
124+ currentPattern : screen ,
125+ depth : 0 ,
126+ } ) )
127+ )
128+
129+ let iterations = 0
130+ while ( patternQueue . size > 0 ) {
131+ iterations += 1
136132
137- while ( queue . size > 0 ) {
138- globalMutableState . queueIterations += 1
139- const { currentPattern, depth } = queue . shift ( ) !
133+ const entry = patternQueue . shift ( )
140134
141- if ( depth > MAX_DEPTH ) break
142- // Always render to MIN_DEPTH even if the draw call budget is empty
143- if ( depth > MIN_DEPTH && globalMutableState . drawScreenCalls >= MAX_DRAW_CALLS ) break
135+ yield entry
144136
145- globalMutableState . drawScreenCalls += 1
146- drawScreen ( ctx , screenSize , currentPattern , COLORS [ Math . min ( COLORS . length - 1 , depth ) ] ! )
137+ // Don't add patterns that are too deep.
138+ if ( entry . depth >= MAX_DEPTH ) {
139+ console . log ( `MAX_DEPTH (${ MAX_DEPTH } ) reached at depth ${ entry . depth } . Breaking from generateDrawQueue loop.` )
140+ break
141+ }
147142
148143 for ( const pattern of state . patterns ) {
149- const virtualScreen = combinePatterns ( currentPattern , pattern )
144+ const virtualScreen = combinePatterns ( entry . currentPattern , pattern )
150145
151146 if ( isValidPattern ( virtualScreen ) ) {
152- queue . push ( {
147+ patternQueue . push ( {
153148 currentPattern : virtualScreen ,
154- depth : depth + 1 ,
149+ depth : entry . depth + 1 ,
155150 } )
156151 }
157152 }
158153
159- globalMutableState . maxQueueSize = Math . max ( globalMutableState . maxQueueSize , queue . size )
154+ // Give up if queue becomes too large.
155+ if ( patternQueue . size > MAX_QUEUE_SIZE ) {
156+ console . warn ( 'Maximum queue size reached. Rendering cancelled.' )
157+ return
158+ }
160159 }
160+
161+ console . log ( `generateDrawQueue done. Total iterations: ${ iterations } . Final queue size: ${ patternQueue . size } ` )
161162}
162163
163164export function * drawFrameIncrementally (
164165 ctx : CanvasRenderingContext2D ,
165166 state : State
166167) : Generator < void , void , void > {
167168 ctx . clearRect ( 0 , 0 , ctx . canvas . width , ctx . canvas . height )
169+ ctx . fillStyle = 'black'
170+ ctx . lineWidth = 1
171+
172+ const screenSize = getScreenSize ( ctx )
168173
169- const drawQueue = new Queue (
170- state . screens . map ( screen => ( {
171- currentPattern : screen ,
172- depth : 0 ,
173- } ) )
174- )
174+ const drawQueueIterator = generateDrawQueue ( state )
175175
176- while ( drawQueue . size > 0 ) {
177- const globalMutableState : GlobalMutableState = {
178- drawScreenCalls : 0 ,
179- maxQueueSize : drawQueue . size ,
180- queueIterations : 0 ,
181- }
176+ while ( true ) {
177+ let drawScreenCalls = 0
182178
183179 const duration = measure ( ( ) => {
184- draw ( ctx , state , globalMutableState , drawQueue )
185- drawQueue . compact ( )
180+ // Manual iteration
181+ while ( true ) {
182+ const iteratorResult = drawQueueIterator . next ( )
183+
184+ if ( iteratorResult . done ) break
185+
186+ const { currentPattern, depth } = iteratorResult . value
187+
188+ drawScreenCalls += 1
189+
190+ drawScreen ( ctx , screenSize , currentPattern , COLORS [ Math . min ( COLORS . length - 1 , depth ) ] ! )
191+
192+ if ( depth > MIN_DEPTH && drawScreenCalls >= MAX_DRAW_CALLS ) break
193+ }
186194 } )
187195
188196 if ( DEBUG ) {
189- console . log (
190- `drawFrame done in ${ duration . toFixed ( 0 ) } ms. Queue size: ${ drawQueue . size } . ${ JSON . stringify ( globalMutableState ) } .`
191- )
197+ console . log ( `drawFrame done in ${ duration . toFixed ( 0 ) } ms. Drew ${ drawScreenCalls } screens.` )
192198 }
193199
194- // Give up if queue becomes too large.
195- if ( drawQueue . size > MAX_QUEUE_SIZE ) {
196- console . warn ( 'Maximum queue size reached. Rendering cancelled.' )
197- return
200+ if ( drawScreenCalls === 0 ) {
201+ console . log ( 'No screens to draw. Exiting.' )
202+ break
198203 }
199204
200205 yield
0 commit comments