@@ -251,56 +251,258 @@ function calculateAdjacency(tileIdx, tileId, tiles, tileset, w, h) {
251251const tilesetMap = new Map ( )
252252const imgMap = new Map ( )
253253
254- async function loadTileset ( tilesetPath ) {
255- console . log ( tilesetPath )
256- if ( tilesetMap . has ( tilesetPath ) ) return tilesetMap . get ( tilesetPath )
257-
258- const fetchPromise = ( async ( ) => {
259-
260- const res = await fetch ( tilesetPath )
261- const rawJson = await res . json ( )
262- const tilesetJson = rawJson . tiles
263- const tileset = { }
264- const path = rawJson . path
265-
266- const promises = tilesetJson . map ( async ( def ) => {
267- const img = new Image ( )
268- img . src = path + def . file
269- await new Promise ( resolve => {
270- img . onload = resolve
271- img . onerror = resolve
272- } )
254+ async function loadSpriteSheetTileset ( manifest ) {
255+ const tileset = [ ]
256+ const raw = await fetch ( manifest . spritesheetPath )
257+ const blob = await raw . blob ( )
258+
259+ const spriteSheet = await new Promise ( ( resolve , reject ) => {
260+ const img = new Image ( )
261+ img . onload = ( ) => resolve ( img )
262+ img . onerror = reject
263+ img . src = manifest . spritesheetPath
264+ } )
265+
266+ const tileWidth = manifest . tileWidth
267+ const width = spriteSheet . naturalWidth / tileWidth
268+ console . log ( `width: ${ width } ` )
269+ for ( const tile of manifest . tiles ) {
270+ const dpr = window . devicePixelRatio
271+ const canvas = document . createElement ( "canvas" )
272+ const ctx = canvas . getContext ( '2d' )
273+ canvas . width = width
274+ canvas . height = width
275+ ctx . imageSmoothingEnabled = false
276+ canvas . style . imageRendering = 'pixelated'
277+
278+ ctx . drawImage ( spriteSheet , tile . x * width , tile . y * width , width , width , 0 , 0 , width , width )
279+
280+ const images = [ ]
281+
282+ if ( tile . type === "adjacency" ) {
283+ for ( let i = 0 ; i < 16 ; i ++ ) {
284+ const subCanvas = document . createElement ( "canvas" )
285+ const subCtx = subCanvas . getContext ( "2d" )
286+ subCtx . setTransform ( dpr , 0 , 0 , dpr , 0 , 0 )
287+ subCanvas . width = width
288+ subCanvas . height = width
289+ subCtx . imageSmoothingEnabled = false
290+ subCanvas . style . imageRendering = 'pixelated'
291+
292+ let x = tile . x + i
293+ let y = tile . y
294+
295+ if ( x >= tileWidth ) {
296+ y = Math . floor ( x / tileWidth ) + y
297+ x = x % tileWidth
298+ }
299+ subCtx . drawImage ( spriteSheet , x * width , y * width , width , width , 0 , 0 , width , width )
300+ images . push ( subCanvas )
301+ }
302+ } else if ( tile . type === "rotation" ) {
303+ for ( let i = 0 ; i < 4 ; i ++ ) {
304+ const subCanvas = document . createElement ( "canvas" )
305+ const subCtx = subCanvas . getContext ( "2d" )
306+ subCtx . setTransform ( dpr , 0 , 0 , dpr , 0 , 0 )
307+ subCanvas . width = width
308+ subCanvas . height = width
309+ subCtx . imageSmoothingEnabled = false
310+ subCanvas . style . imageRendering = 'pixelated'
311+
312+ let x = tile . x + i
313+ let y = tile . y
314+
315+ if ( x >= tileWidth ) {
316+ y = Math . floor ( x / tileWidth ) + y
317+ x = x % tileWidth
318+ }
319+ subCtx . drawImage ( spriteSheet , x * width , y * width , width , width , 0 , 0 , width , width )
320+ images . push ( subCanvas )
321+ }
322+ }
323+
324+ let minimapColor = 'rgba(0, 0, 0, 0)'
325+ try {
326+ const imgData = ctx . getImageData ( 0 , 0 , width , width ) . data
327+ const colorCounts = { }
328+ let maxCount = 0
329+ for ( let i = 0 ; i < imgData . length ; i += 4 ) {
330+ const r = imgData [ i ]
331+ const g = imgData [ i + 1 ]
332+ const b = imgData [ i + 2 ]
333+ const a = imgData [ i + 3 ]
334+
335+ if ( a < 128 ) continue
336+ const rgb = `rgb(${ r } , ${ g } , ${ b } )`
337+ colorCounts [ rgb ] = ( colorCounts [ rgb ] || 0 ) + 1
338+
339+ if ( colorCounts [ rgb ] > maxCount ) {
340+ maxCount = colorCounts [ rgb ]
341+ minimapColor = rgb
342+ }
343+ }
344+ } catch ( e ) {
345+ console . warn ( "could not calculate minimap color" , e )
346+ }
273347
274- tileset [ def . id ] = { ...def , triggerAdjacency : def . triggerAdjacency , image : img , images : [ ] }
348+ const tileObject = {
349+ ...tile ,
350+ minimapColor : minimapColor ,
351+ image : canvas ,
352+ }
353+ if ( images . length > 0 ) {
354+ tileObject . images = images
355+ }
356+ tileset . push ( tileObject )
357+ }
358+ console . log ( tileset )
359+ return tileset
360+ }
275361
276- if ( def . type == "adjacency" || def . type == "rotation" ) {
277- const w = img . naturalHeight
278- if ( w > 0 ) {
279- const count = Math . floor ( img . naturalWidth / w )
280- for ( let i = 0 ; i < count ; i ++ ) {
362+ export function splitStripImages ( tileset ) {
363+ // split strip images
364+ const newTileset = [ ]
365+ tileset . forEach ( tile => {
366+ if ( ! tile ) return
367+ if ( tile . images ) {
368+ newTileset [ tile . id ] = tile
369+ return
370+ }
371+ if ( tile . type === 'adjacency' && tile . image ) {
372+ // split the strip into different pieces here
373+ const h = tile . image . naturalHeight
374+ const w = tile . image . naturalWidth
375+ const sublist = [ ]
376+ for ( let i = 0 ; i < 16 ; i ++ ) {
377+ const c = document . createElement ( 'canvas' )
378+ c . width = h
379+ c . height = h
380+ const ctx = c . getContext ( '2d' )
381+ ctx . drawImage ( tile . image , i * h , 0 , h , h , 0 , 0 , h , h )
382+
383+ sublist . push ( c )
384+ }
385+ newTileset [ tile . id ] = { ...tile , images : sublist }
386+ } else if ( tile . type == 'rotation' ) {
387+ const h = tile . image . naturalHeight
388+ const w = tile . image . naturalWidth
389+ const sublist = [ ]
390+ if ( w == h * 4 ) {
391+ for ( let i = 0 ; i < 4 ; i ++ ) {
392+ const c = document . createElement ( 'canvas' )
393+ c . width = h
394+ c . height = h
395+ const ctx = c . getContext ( '2d' )
396+ ctx . drawImage ( tile . image , i * h , 0 , h , h , 0 , 0 , h , h )
397+ sublist . push ( c )
398+ }
399+ newTileset [ tile . id ] = { ...tile , images : sublist }
400+ } else if ( w == h * 8 ) {
401+ for ( let i = 0 ; i < 8 ; i ++ ) {
402+ const c = document . createElement ( 'canvas' )
403+ c . width = h
404+ c . height = h
405+ const ctx = c . getContext ( '2d' )
406+ ctx . drawImage ( tile . image , i * h , 0 , h , h , 0 , 0 , h , h )
407+ sublist . push ( c )
408+ }
409+ newTileset [ tile . id ] = { ...tile , images : sublist }
410+ }
411+ } else {
412+ newTileset [ tile . id ] = tile
413+ }
414+ } )
415+ return newTileset
416+ }
417+
418+ export async function loadTileset ( manifestPath ) {
419+ if ( manifestPath === "/assets/medium-spritesheet.json" ) manifestPath = "/assets/medium.json"
420+ if ( tilesetMap . has ( manifestPath ) ) {
421+ const tileset = tilesetMap . get ( manifestPath )
422+ return tileset
423+ }
424+
425+ const fetchPromise = fetch ( manifestPath )
426+ . then ( response => response . json ( ) )
427+ . then ( async ( manifest ) => {
428+ if ( manifest . type == "spritesheet" ) {
429+ const tileset = await loadSpriteSheetTileset ( manifest )
430+
431+ const characterImage = await new Promise ( ( resolve ) => {
432+ const img = new Image ( )
433+ const prefix = manifest . path + "/"
434+ img . onload = ( ) => resolve ( img )
435+ img . onerror = ( e ) => {
436+ console . error ( `failed to load character image from: ${ srcPath } ` , e )
437+ resolve ( null )
438+ }
439+ img . src = prefix + manifest . characterFile
440+ } )
441+
442+ tilesetMap . set ( manifestPath , tileset )
443+ console . log ( characterImage )
444+ return tileset
445+ }
446+
447+ let loadedCount = 0
448+ const totalCount = manifest . tiles . length + 1
449+
450+ function updateProgress ( ) {
451+ loadedCount ++
452+ window . dispatchEvent ( new CustomEvent ( 'loading:progress' , {
453+ detail : { loaded : loadedCount , total : totalCount }
454+ } ) )
455+ }
456+
457+ const promises = manifest . tiles . map ( tileData => {
458+
459+ if ( ! tileData . file ) {
460+ updateProgress ( )
461+ return Promise . resolve ( tileData )
462+ }
463+ return new Promise ( ( resolve , reject ) => {
464+ const img = new Image ( )
465+ img . src = manifest . path + tileData . file
466+ img . onload = ( ) => {
281467 const canvas = document . createElement ( 'canvas' )
282- canvas . width = w
283- canvas . height = w
284468 const ctx = canvas . getContext ( '2d' )
285- ctx . drawImage ( img , i * w , 0 , w , w , 0 , 0 , w , w )
469+ canvas . width = img . height || 1
470+ canvas . height = img . height || 1
471+ ctx . drawImage ( img , 0 , 0 )
286472
287- const sliceImg = new Image ( )
288- sliceImg . src = canvas . toDataURL ( )
289- tileset [ def . id ] . images [ i ] = sliceImg
473+ updateProgress ( )
474+ resolve ( { ...tileData , image : img } )
290475 }
291- }
292- }
476+ img . onerror = ( e ) => {
477+ updateProgress ( )
478+ reject ( e )
479+ }
480+ } )
481+ } )
482+
483+ return Promise . all ( promises )
484+ . then ( ( items ) => {
485+ const tileset = [ ]
486+ items . forEach ( item => {
487+ tileset [ item . id ] = item
488+ } )
489+
490+ tilesetMap . set ( manifestPath , tileset )
491+ return tileset
492+ } )
493+
293494 } )
294- await Promise . all ( promises )
295- return tileset
296- } ) ( ) ;
297- tilesetMap . set ( tilesetPath , fetchPromise )
298- console . log ( tilesetMap . has ( tilesetPath ) )
495+
496+ tilesetMap . set ( manifestPath , fetchPromise )
497+
299498 return fetchPromise
499+
300500}
301501
502+
302503export async function renderLevelPreview ( canvas , levelData ) {
303504 let tileset = await loadTileset ( levelData . data . tilesetPath )
505+ tileset = splitStripImages ( tileset )
304506 tileset = Object . values ( tileset )
305507 if ( ! canvas || ! levelData ) return
306508
@@ -324,7 +526,7 @@ export async function renderLevelPreview(canvas, levelData) {
324526
325527 const rotationData = decodeRLE ( levelData . data . layers [ 1 ] ? levelData . data . layers [ 1 ] . data : [ ] )
326528
327- const spawnId = tileset . find ( f => f . mechanics && f . mechanics . includes ( "spawn" ) ) . id
529+ const spawnId = tileset . find ( f => f . mechanics && f . mechanics . includes ( "spawn" ) ) ? .id
328530 const spawnIdx = decoded . findIndex ( f => f == spawnId )
329531
330532 let spawnX = 0
0 commit comments