From e9227e4166cec2d08284587ae99796f545763b82 Mon Sep 17 00:00:00 2001 From: candle Date: Tue, 28 May 2024 14:04:35 +0100 Subject: [PATCH 1/3] rendering based on ordered draw calls --- src/scripts/playback.js | 86 ++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/src/scripts/playback.js b/src/scripts/playback.js index 1c1efd2..574d2db 100644 --- a/src/scripts/playback.js +++ b/src/scripts/playback.js @@ -540,7 +540,7 @@ class BipsiPlayback extends EventTarget { this.render(); } - render(frame=undefined) { + addRoomToScene(scene, dest, frame) { // find avatar, current room, current palette const avatar = getEventById(this.data, this.avatarId); const room = roomFromEvent(this.data, avatar); @@ -548,50 +548,64 @@ class BipsiPlayback extends EventTarget { const tileset = this.stateManager.resources.get(this.data.tileset); // find current animation frame for each tile - frame = frame ?? this.frameCount; const tileToFrame = makeTileToFrameMap(this.data.tiles, frame); - // sort images - const images = Array.from(this.images.values()); - images.sort((a, b) => a.layer - b.layer); - const images_below_all = images.filter((image) => image.layer < 1); - const images_below_events = images.filter((image) => image.layer >= 1 && image.layer < 2); - const images_above_events = images.filter((image) => image.layer >= 2 && image.layer < 3); - const images_above_all = images.filter((image) => image.layer >= 3); + function upscaler(func) { + return () => { + fillRendering2D(TEMP_ROOM); + func(); + dest.drawImage(TEMP_ROOM.canvas, 0, 0, 256, 256); + }; + } + scene.push({ layer: 1, func: upscaler(() => drawTilemapLayer(TEMP_ROOM, tileset, tileToFrame, palette, room)) }); + scene.push({ layer: 2, func: upscaler(() => drawEventLayer(TEMP_ROOM, tileset, tileToFrame, palette, room.events)) }); + } + + addImagesToScene(scene, dest, frame) { function drawImage({ image, x, y }) { - TEMP_ROOM.drawImage(image[frame % image.length], x, y); + dest.drawImage(image[frame % image.length], x, y); } - fillRendering2D(this.rendering); - images_below_all.forEach(drawImage); - drawTilemapLayer(TEMP_ROOM, tileset, tileToFrame, palette, room); - images_below_events.forEach(drawImage); - drawEventLayer(TEMP_ROOM, tileset, tileToFrame, palette, room.events); - images_above_events.forEach(drawImage); - - // upscale tilemaps to display area - this.rendering.drawImage(TEMP_ROOM.canvas, 0, 0, 256, 256); - - // render dialogue box if necessary - if (!this.dialoguePlayback.empty) { - // change default dialogue position based on avatar position - const top = avatar.position[1] >= 8; - this.dialoguePlayback.options.anchorY = top ? 0 : 1; - - // redraw dialogue and copy to display area - this.dialoguePlayback.render(); - this.rendering.drawImage(this.dialoguePlayback.dialogueRendering.canvas, 0, 0); - } - - fillRendering2D(TEMP_ROOM); - images_above_all.forEach(drawImage); - this.rendering.drawImage(TEMP_ROOM.canvas, 0, 0, 256, 256); + const images = [...this.images.values()]; + const draws = images.map((image) => ({ layer: image.layer, func: () => drawImage(image) })); - if (this.ended) { - fillRendering2D(this.rendering); + scene.push(...draws); + } + + addDialogueToScene(scene, dest, frame) { + if (this.dialoguePlayback.empty) + return; + + // change default dialogue position based on avatar position + const avatar = getEventById(this.data, this.avatarId); + const top = avatar.position[1] >= 8; + this.dialoguePlayback.options.anchorY = top ? 0 : 1; + + // redraw dialogue and copy to display area + this.dialoguePlayback.render(); + scene.push({ layer: 3, func: () => dest.drawImage(this.dialoguePlayback.dialogueRendering.canvas, 0, 0) }); + } + + render(frame=undefined) { + frame = frame ?? this.frameCount; + + const scene = []; + + // add visual layers to scene + if (!this.ended) { + this.addImagesToScene(scene, this.rendering, frame); + this.addRoomToScene(scene, this.rendering, frame); + this.addDialogueToScene(scene, this.rendering, frame); } + // sort visual layers + scene.sort((a, b) => a.layer - b.layer); + + // clear and draw layers + fillRendering2D(this.rendering); + scene.forEach(({ func }) => func()); + // signal, to anyone listening, that rendering happened this.dispatchEvent(new CustomEvent("render")); } From c302af0f6bd164aa99d241864b2d1f18c9c599b5 Mon Sep 17 00:00:00 2001 From: candle Date: Sat, 1 Jun 2024 16:09:22 +0100 Subject: [PATCH 2/3] split out more --- src/scripts/playback.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/scripts/playback.js b/src/scripts/playback.js index 574d2db..2d7f08f 100644 --- a/src/scripts/playback.js +++ b/src/scripts/playback.js @@ -587,17 +587,21 @@ class BipsiPlayback extends EventTarget { scene.push({ layer: 3, func: () => dest.drawImage(this.dialoguePlayback.dialogueRendering.canvas, 0, 0) }); } + addLayersToScene(scene, dest, frame) { + if (!this.ended) { + this.addRoomToScene(scene, dest, frame); + this.addDialogueToScene(scene, dest, frame); + this.addImagesToScene(scene, dest, frame); + } + } + render(frame=undefined) { frame = frame ?? this.frameCount; const scene = []; // add visual layers to scene - if (!this.ended) { - this.addImagesToScene(scene, this.rendering, frame); - this.addRoomToScene(scene, this.rendering, frame); - this.addDialogueToScene(scene, this.rendering, frame); - } + this.addLayersToScene(scene, this.rendering, frame); // sort visual layers scene.sort((a, b) => a.layer - b.layer); From 851898b4aab81c51d5a6b936f4408c9e3696d064 Mon Sep 17 00:00:00 2001 From: candle Date: Sat, 1 Jun 2024 16:19:50 +0100 Subject: [PATCH 3/3] midground layer --- docs/event-behaviors.md | 3 +++ src/scripts/playback.js | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/docs/event-behaviors.md b/docs/event-behaviors.md index 1e27069..d3c943c 100644 --- a/docs/event-behaviors.md +++ b/docs/event-behaviors.md @@ -69,15 +69,18 @@ | image layer | meaning |--|-- | background | below the room, events, and dialogue +| midground | above the room, but below the events and dialogue | foreground | above the room and events, but below the dialogue | overlay | above the room, events, and dialogue | name | type | meaning |--|--|-- | background | text | show named image on background layer +| midground | text | show named image on midground layer | foreground | text | show named image on foreground layer | overlay | text | show named image on overlay layer | clear-background | tag | clear image on background layer +| clear-midground | tag | clear image on midground layer | clear-foreground | tag | clear image on foreground layer | clear-overlay | tag | clear image on overlay layer diff --git a/src/scripts/playback.js b/src/scripts/playback.js index 2d7f08f..36f8a44 100644 --- a/src/scripts/playback.js +++ b/src/scripts/playback.js @@ -241,6 +241,13 @@ if (backgrounds.length > 0) { HIDE_IMAGE("BACKGROUND"); } +let midgrounds = FIELDS_OR_LIBRARY("midground"); +if (midgrounds.length > 0) { + SHOW_IMAGE("MIDGROUND", midgrounds, 1, 0, 0); +} else if (IS_TAGGED(EVENT, "clear-midground")) { + HIDE_IMAGE("MIDGROUND"); +} + let foregrounds = FIELDS_OR_LIBRARY("foreground"); if (foregrounds.length > 0) { SHOW_IMAGE("FOREGROUND", foregrounds, 2, 0, 0);