Split out editor drawing and slightly speed up normal drawing
This commit is contained in:
parent
6fc4f6b58f
commit
90fa352a50
@ -282,7 +282,7 @@ class EditorLevelBrowserOverlay extends DialogOverlay {
|
|||||||
let stored_level = this.conductor.stored_game.load_level(index);
|
let stored_level = this.conductor.stored_game.load_level(index);
|
||||||
this.renderer.set_level(stored_level);
|
this.renderer.set_level(stored_level);
|
||||||
this.renderer.set_viewport_size(stored_level.size_x, stored_level.size_y);
|
this.renderer.set_viewport_size(stored_level.size_x, stored_level.size_y);
|
||||||
this.renderer.draw();
|
this.renderer.draw_static_region(0, 0, stored_level.size_x, stored_level.size_y);
|
||||||
let canvas = mk('canvas', {
|
let canvas = mk('canvas', {
|
||||||
width: stored_level.size_x * this.conductor.tileset.size_x / 4,
|
width: stored_level.size_x * this.conductor.tileset.size_x / 4,
|
||||||
height: stored_level.size_y * this.conductor.tileset.size_y / 4,
|
height: stored_level.size_y * this.conductor.tileset.size_y / 4,
|
||||||
@ -2424,7 +2424,7 @@ export class Editor extends PrimaryView {
|
|||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
// FIXME eventually this should be automatic
|
// FIXME eventually this should be automatic
|
||||||
this.renderer.draw();
|
this.redraw_entire_level();
|
||||||
}
|
}
|
||||||
else if (ev.button === 1) {
|
else if (ev.button === 1) {
|
||||||
// Middle button: always pan
|
// Middle button: always pan
|
||||||
@ -2443,7 +2443,7 @@ export class Editor extends PrimaryView {
|
|||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
this.renderer.draw();
|
this.redraw_entire_level();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Once the mouse is down, we should accept mouse movement anywhere
|
// Once the mouse is down, we should accept mouse movement anywhere
|
||||||
@ -2471,7 +2471,7 @@ export class Editor extends PrimaryView {
|
|||||||
this.mouse_op.do_mousemove(ev);
|
this.mouse_op.do_mousemove(ev);
|
||||||
|
|
||||||
// FIXME !!!
|
// FIXME !!!
|
||||||
this.renderer.draw();
|
this.redraw_entire_level();
|
||||||
});
|
});
|
||||||
// TODO should this happen for a mouseup anywhere?
|
// TODO should this happen for a mouseup anywhere?
|
||||||
this.viewport_el.addEventListener('mouseup', ev => {
|
this.viewport_el.addEventListener('mouseup', ev => {
|
||||||
@ -2720,7 +2720,7 @@ export class Editor extends PrimaryView {
|
|||||||
|
|
||||||
activate() {
|
activate() {
|
||||||
super.activate();
|
super.activate();
|
||||||
this.renderer.draw();
|
this.redraw_entire_level();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Level creation, management, and saving
|
// Level creation, management, and saving
|
||||||
@ -2934,7 +2934,7 @@ export class Editor extends PrimaryView {
|
|||||||
|
|
||||||
this.renderer.set_level(stored_level);
|
this.renderer.set_level(stored_level);
|
||||||
if (this.active) {
|
if (this.active) {
|
||||||
this.renderer.draw();
|
this.redraw_entire_level();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.save_button) {
|
if (this.save_button) {
|
||||||
@ -3073,6 +3073,8 @@ export class Editor extends PrimaryView {
|
|||||||
this.palette_actor_direction = DIRECTIONS[this.palette_actor_direction].left;
|
this.palette_actor_direction = DIRECTIONS[this.palette_actor_direction].left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- Drawing --
|
||||||
|
|
||||||
mark_tile_dirty(tile) {
|
mark_tile_dirty(tile) {
|
||||||
// TODO partial redraws! until then, redraw everything
|
// TODO partial redraws! until then, redraw everything
|
||||||
if (tile === this.palette_selection) {
|
if (tile === this.palette_selection) {
|
||||||
@ -3081,14 +3083,20 @@ export class Editor extends PrimaryView {
|
|||||||
this.selected_tile_el.append(this.renderer.create_tile_type_canvas(tile.type.name, tile));
|
this.selected_tile_el.append(this.renderer.create_tile_type_canvas(tile.type.name, tile));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.renderer.draw();
|
this.redraw_entire_level();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mark_cell_dirty(cell) {
|
mark_cell_dirty(cell) {
|
||||||
this.renderer.draw();
|
this.redraw_entire_level();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
redraw_entire_level() {
|
||||||
|
this.renderer.draw_static_region(0, 0, this.stored_level.size_x, this.stored_level.size_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- Utility/inspection --
|
||||||
|
|
||||||
is_in_bounds(x, y) {
|
is_in_bounds(x, y) {
|
||||||
return 0 <= x && x < this.stored_level.size_x && 0 <= y && y < this.stored_level.size_y;
|
return 0 <= x && x < this.stored_level.size_x && 0 <= y && y < this.stored_level.size_y;
|
||||||
}
|
}
|
||||||
@ -3102,6 +3110,8 @@ export class Editor extends PrimaryView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- Mutation --
|
||||||
|
|
||||||
place_in_cell(x, y, tile) {
|
place_in_cell(x, y, tile) {
|
||||||
// TODO weird api?
|
// TODO weird api?
|
||||||
if (! tile)
|
if (! tile)
|
||||||
@ -3167,6 +3177,8 @@ export class Editor extends PrimaryView {
|
|||||||
this.mark_cell_dirty(cell);
|
this.mark_cell_dirty(cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -- Misc?? --
|
||||||
|
|
||||||
open_tile_prop_overlay(tile, x0, y0) {
|
open_tile_prop_overlay(tile, x0, y0) {
|
||||||
this.cancel_mouse_operation();
|
this.cancel_mouse_operation();
|
||||||
// FIXME keep these around, don't recreate them constantly
|
// FIXME keep these around, don't recreate them constantly
|
||||||
@ -3222,6 +3234,6 @@ export class Editor extends PrimaryView {
|
|||||||
this.stored_level.size_x = size_x;
|
this.stored_level.size_x = size_x;
|
||||||
this.stored_level.size_y = size_y;
|
this.stored_level.size_y = size_y;
|
||||||
this.update_viewport_size();
|
this.update_viewport_size();
|
||||||
this.renderer.draw();
|
this.redraw_entire_level();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -105,21 +105,11 @@ export class CanvasRenderer {
|
|||||||
// TODO what about levels smaller than the viewport...? shrink the canvas in set_level?
|
// TODO what about levels smaller than the viewport...? shrink the canvas in set_level?
|
||||||
let xmargin = (this.viewport_size_x - 1) / 2;
|
let xmargin = (this.viewport_size_x - 1) / 2;
|
||||||
let ymargin = (this.viewport_size_y - 1) / 2;
|
let ymargin = (this.viewport_size_y - 1) / 2;
|
||||||
let px, py;
|
let [px, py] = this.level.player.visual_position(tic_offset);
|
||||||
// FIXME editor vs player
|
|
||||||
if (this.level.player) {
|
|
||||||
[px, py] = this.level.player.visual_position(tic_offset);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
[px, py] = [0, 0];
|
|
||||||
}
|
|
||||||
// Figure out where to start drawing
|
// Figure out where to start drawing
|
||||||
// TODO support overlapping regions better
|
// TODO support overlapping regions better
|
||||||
let x0 = px - xmargin;
|
let x0 = px - xmargin;
|
||||||
let y0 = py - ymargin;
|
let y0 = py - ymargin;
|
||||||
// FIXME editor vs player again ugh, which is goofy since none of this is even relevant;
|
|
||||||
// maybe need to have a separate positioning method
|
|
||||||
if (this.level.stored_level) {
|
|
||||||
for (let region of this.level.stored_level.camera_regions) {
|
for (let region of this.level.stored_level.camera_regions) {
|
||||||
if (px >= region.left && px < region.right &&
|
if (px >= region.left && px < region.right &&
|
||||||
py >= region.top && py < region.bottom)
|
py >= region.top && py < region.bottom)
|
||||||
@ -128,7 +118,6 @@ export class CanvasRenderer {
|
|||||||
y0 = Math.max(region.top, Math.min(region.bottom - this.viewport_size_y, y0));
|
y0 = Math.max(region.top, Math.min(region.bottom - this.viewport_size_y, y0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// Always keep us within the map bounds
|
// Always keep us within the map bounds
|
||||||
x0 = Math.max(0, Math.min(this.level.size_x - this.viewport_size_x, x0));
|
x0 = Math.max(0, Math.min(this.level.size_x - this.viewport_size_x, x0));
|
||||||
y0 = Math.max(0, Math.min(this.level.size_y - this.viewport_size_y, y0));
|
y0 = Math.max(0, Math.min(this.level.size_y - this.viewport_size_y, y0));
|
||||||
@ -152,55 +141,67 @@ export class CanvasRenderer {
|
|||||||
// include the tiles just outside it, so we allow this fencepost problem to fly
|
// include the tiles just outside it, so we allow this fencepost problem to fly
|
||||||
let x1 = Math.min(this.level.size_x - 1, Math.ceil(x0 + this.viewport_size_x));
|
let x1 = Math.min(this.level.size_x - 1, Math.ceil(x0 + this.viewport_size_x));
|
||||||
let y1 = Math.min(this.level.size_y - 1, Math.ceil(y0 + this.viewport_size_y));
|
let y1 = Math.min(this.level.size_y - 1, Math.ceil(y0 + this.viewport_size_y));
|
||||||
// Draw one layer at a time, so animated objects aren't overdrawn by
|
// Tiles in motion (i.e., actors) don't want to be overdrawn by neighboring tiles' terrain,
|
||||||
|
// so draw in three passes: everything below actors, actors, and everything above actors
|
||||||
// neighboring terrain
|
// neighboring terrain
|
||||||
// FIXME this is a bit inefficient when there are a lot of rarely-used layers; consider
|
|
||||||
// instead drawing everything under actors, then actors, then everything above actors?
|
|
||||||
// (note: will need to first fix the game to ensure everything is stacked correctly!)
|
|
||||||
for (let layer = 0; layer < LAYERS.MAX; layer++) {
|
|
||||||
for (let x = xf0; x <= x1; x++) {
|
for (let x = xf0; x <= x1; x++) {
|
||||||
for (let y = yf0; y <= y1; y++) {
|
for (let y = yf0; y <= y1; y++) {
|
||||||
let cell = this.level.cell(x, y);
|
let cell = this.level.cell(x, y);
|
||||||
|
for (let layer = 0; layer < LAYERS.actor; layer++) {
|
||||||
let tile = cell[layer];
|
let tile = cell[layer];
|
||||||
if (! tile)
|
if (! tile)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let vx, vy;
|
this.tileset.draw(
|
||||||
if (tile.type.is_actor &&
|
tile, tic, this.perception,
|
||||||
// FIXME kind of a hack for the editor, which uses bare tile objects
|
this._make_tileset_blitter(this.ctx, x - x0, y - y0));
|
||||||
tile.visual_position)
|
}
|
||||||
{
|
}
|
||||||
|
}
|
||||||
|
for (let x = xf0; x <= x1; x++) {
|
||||||
|
for (let y = yf0; y <= y1; y++) {
|
||||||
|
let cell = this.level.cell(x, y);
|
||||||
|
let actor = cell[LAYERS.actor];
|
||||||
|
if (! actor)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Handle smooth scrolling
|
// Handle smooth scrolling
|
||||||
[vx, vy] = tile.visual_position(tic_offset);
|
let [vx, vy] = actor.visual_position(tic_offset);
|
||||||
// Round this to the pixel grid too!
|
// Round this to the pixel grid too!
|
||||||
vx = Math.floor(vx * tw + 0.5) / tw;
|
vx = Math.floor(vx * tw + 0.5) / tw;
|
||||||
vy = Math.floor(vy * th + 0.5) / th;
|
vy = Math.floor(vy * th + 0.5) / th;
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Non-actors can't move
|
|
||||||
vx = x;
|
|
||||||
vy = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For actors (i.e., blocks), perception only applies if there's something
|
// For actors (i.e., blocks), perception only applies if there's something of
|
||||||
// of potential interest underneath
|
// potential interest underneath
|
||||||
let perception = this.perception;
|
let perception = this.perception;
|
||||||
if (perception !== 'normal' && tile.type.is_actor &&
|
if (perception !== 'normal' &&
|
||||||
! cell.some(t =>
|
! cell.some(t => t && t.type.layer < layer && ! (
|
||||||
t && t.type.layer < layer &&
|
t.type.name === 'floor' && (t.wire_directions | t.wire_tunnel_directions) === 0)))
|
||||||
! (t.type.name === 'floor' && (t.wire_directions | t.wire_tunnel_directions) === 0)))
|
|
||||||
{
|
{
|
||||||
perception = 'normal';
|
perception = 'normal';
|
||||||
}
|
}
|
||||||
|
|
||||||
this.tileset.draw(
|
this.tileset.draw(
|
||||||
tile, tic, perception,
|
actor, tic, perception,
|
||||||
this._make_tileset_blitter(this.ctx, vx - x0, vy - y0));
|
this._make_tileset_blitter(this.ctx, vx - x0, vy - y0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (let x = xf0; x <= x1; x++) {
|
||||||
|
for (let y = yf0; y <= y1; y++) {
|
||||||
|
let cell = this.level.cell(x, y);
|
||||||
|
for (let layer = LAYERS.actor + 1; layer < LAYERS.MAX; layer++) {
|
||||||
|
let tile = cell[layer];
|
||||||
|
if (! tile)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this.tileset.draw(
|
||||||
|
tile, tic, this.perception,
|
||||||
|
this._make_tileset_blitter(this.ctx, x - x0, y - y0));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.show_actor_bboxes && this.level.constructor.name === 'Level') { // FIXME dumb hack so this doesn't happen in editor
|
if (this.show_actor_bboxes) {
|
||||||
this.ctx.fillStyle = '#f004';
|
this.ctx.fillStyle = '#f004';
|
||||||
for (let x = xf0; x <= x1; x++) {
|
for (let x = xf0; x <= x1; x++) {
|
||||||
for (let y = yf0; y <= y1; y++) {
|
for (let y = yf0; y <= y1; y++) {
|
||||||
@ -233,6 +234,41 @@ export class CanvasRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used by the editor and map previews. Draws a region of the level (probably a StoredLevel),
|
||||||
|
// assuming nothing is moving.
|
||||||
|
draw_static_region(x0, y0, x1, y1, destx = x0, desty = y0) {
|
||||||
|
for (let x = x0; x <= x1; x++) {
|
||||||
|
for (let y = y0; y <= y1; y++) {
|
||||||
|
let cell = this.level.cell(x, y);
|
||||||
|
if (! cell)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let seen_anything_interesting;
|
||||||
|
for (let tile of cell) {
|
||||||
|
if (! tile)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// For actors (i.e., blocks), perception only applies if there's something
|
||||||
|
// of potential interest underneath
|
||||||
|
let perception = this.perception;
|
||||||
|
if (perception !== 'normal' && tile.type.is_actor && ! seen_anything_interesting) {
|
||||||
|
perception = 'normal';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tile.type.layer < LAYERS.actor && ! (
|
||||||
|
tile.type.name === 'floor' && (tile.wire_directions | tile.wire_tunnel_directions) === 0))
|
||||||
|
{
|
||||||
|
seen_anything_interesting = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tileset.draw(
|
||||||
|
tile, 0, perception,
|
||||||
|
this._make_tileset_blitter(this.ctx, destx + x - x0, desty + y - y0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
create_tile_type_canvas(name, tile = null) {
|
create_tile_type_canvas(name, tile = null) {
|
||||||
let canvas = mk('canvas', {width: this.tileset.size_x, height: this.tileset.size_y});
|
let canvas = mk('canvas', {width: this.tileset.size_x, height: this.tileset.size_y});
|
||||||
let ctx = canvas.getContext('2d');
|
let ctx = canvas.getContext('2d');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user