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);
|
||||
this.renderer.set_level(stored_level);
|
||||
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', {
|
||||
width: stored_level.size_x * this.conductor.tileset.size_x / 4,
|
||||
height: stored_level.size_y * this.conductor.tileset.size_y / 4,
|
||||
@ -2424,7 +2424,7 @@ export class Editor extends PrimaryView {
|
||||
ev.stopPropagation();
|
||||
|
||||
// FIXME eventually this should be automatic
|
||||
this.renderer.draw();
|
||||
this.redraw_entire_level();
|
||||
}
|
||||
else if (ev.button === 1) {
|
||||
// Middle button: always pan
|
||||
@ -2443,7 +2443,7 @@ export class Editor extends PrimaryView {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
this.renderer.draw();
|
||||
this.redraw_entire_level();
|
||||
}
|
||||
});
|
||||
// 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);
|
||||
|
||||
// FIXME !!!
|
||||
this.renderer.draw();
|
||||
this.redraw_entire_level();
|
||||
});
|
||||
// TODO should this happen for a mouseup anywhere?
|
||||
this.viewport_el.addEventListener('mouseup', ev => {
|
||||
@ -2720,7 +2720,7 @@ export class Editor extends PrimaryView {
|
||||
|
||||
activate() {
|
||||
super.activate();
|
||||
this.renderer.draw();
|
||||
this.redraw_entire_level();
|
||||
}
|
||||
|
||||
// Level creation, management, and saving
|
||||
@ -2934,7 +2934,7 @@ export class Editor extends PrimaryView {
|
||||
|
||||
this.renderer.set_level(stored_level);
|
||||
if (this.active) {
|
||||
this.renderer.draw();
|
||||
this.redraw_entire_level();
|
||||
}
|
||||
|
||||
if (this.save_button) {
|
||||
@ -3073,6 +3073,8 @@ export class Editor extends PrimaryView {
|
||||
this.palette_actor_direction = DIRECTIONS[this.palette_actor_direction].left;
|
||||
}
|
||||
|
||||
// -- Drawing --
|
||||
|
||||
mark_tile_dirty(tile) {
|
||||
// TODO partial redraws! until then, redraw everything
|
||||
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));
|
||||
}
|
||||
else {
|
||||
this.renderer.draw();
|
||||
this.redraw_entire_level();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
// TODO weird api?
|
||||
if (! tile)
|
||||
@ -3167,6 +3177,8 @@ export class Editor extends PrimaryView {
|
||||
this.mark_cell_dirty(cell);
|
||||
}
|
||||
|
||||
// -- Misc?? --
|
||||
|
||||
open_tile_prop_overlay(tile, x0, y0) {
|
||||
this.cancel_mouse_operation();
|
||||
// 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_y = size_y;
|
||||
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?
|
||||
let xmargin = (this.viewport_size_x - 1) / 2;
|
||||
let ymargin = (this.viewport_size_y - 1) / 2;
|
||||
let px, py;
|
||||
// FIXME editor vs player
|
||||
if (this.level.player) {
|
||||
[px, py] = this.level.player.visual_position(tic_offset);
|
||||
}
|
||||
else {
|
||||
[px, py] = [0, 0];
|
||||
}
|
||||
let [px, py] = this.level.player.visual_position(tic_offset);
|
||||
// Figure out where to start drawing
|
||||
// TODO support overlapping regions better
|
||||
let x0 = px - xmargin;
|
||||
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) {
|
||||
if (px >= region.left && px < region.right &&
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
// Always keep us within the map bounds
|
||||
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));
|
||||
@ -152,55 +141,67 @@ export class CanvasRenderer {
|
||||
// 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 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
|
||||
// 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 y = yf0; y <= y1; y++) {
|
||||
let cell = this.level.cell(x, y);
|
||||
for (let layer = 0; layer < LAYERS.actor; layer++) {
|
||||
let tile = cell[layer];
|
||||
if (! tile)
|
||||
continue;
|
||||
|
||||
let vx, vy;
|
||||
if (tile.type.is_actor &&
|
||||
// FIXME kind of a hack for the editor, which uses bare tile objects
|
||||
tile.visual_position)
|
||||
{
|
||||
this.tileset.draw(
|
||||
tile, tic, this.perception,
|
||||
this._make_tileset_blitter(this.ctx, x - x0, y - y0));
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
[vx, vy] = tile.visual_position(tic_offset);
|
||||
let [vx, vy] = actor.visual_position(tic_offset);
|
||||
// Round this to the pixel grid too!
|
||||
vx = Math.floor(vx * tw + 0.5) / tw;
|
||||
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
|
||||
// of potential interest underneath
|
||||
// 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 &&
|
||||
! cell.some(t =>
|
||||
t && t.type.layer < layer &&
|
||||
! (t.type.name === 'floor' && (t.wire_directions | t.wire_tunnel_directions) === 0)))
|
||||
if (perception !== 'normal' &&
|
||||
! cell.some(t => t && t.type.layer < layer && ! (
|
||||
t.type.name === 'floor' && (t.wire_directions | t.wire_tunnel_directions) === 0)))
|
||||
{
|
||||
perception = 'normal';
|
||||
}
|
||||
|
||||
this.tileset.draw(
|
||||
tile, tic, perception,
|
||||
actor, tic, perception,
|
||||
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';
|
||||
for (let x = xf0; x <= x1; x++) {
|
||||
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) {
|
||||
let canvas = mk('canvas', {width: this.tileset.size_x, height: this.tileset.size_y});
|
||||
let ctx = canvas.getContext('2d');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user