246 lines
6.3 KiB
TypeScript
246 lines
6.3 KiB
TypeScript
import { Color, Point, Rect, Size } from "./engine/datatypes.ts";
|
|
import { D } from "./engine/public.ts";
|
|
|
|
export const FLOOR_CELL_SIZE: Size = new Size(48, 48);
|
|
export const CEILING_CELL_SIZE: Size = new Size(56, 56);
|
|
export const HEIGHT_IN_FEET = 12;
|
|
export const CENTER = new Point(192, 192);
|
|
export const MOULDING_SZ = new Size(1, 1);
|
|
|
|
export class GridArt {
|
|
#atPixel: Point;
|
|
|
|
#floorCenter: Point;
|
|
#ceilingCenter: Point;
|
|
#floorTl: Point;
|
|
#ceilingTl: Point;
|
|
#floorBr: Point;
|
|
#ceilingBr: Point;
|
|
|
|
constructor(atPixel: Point) {
|
|
this.#atPixel = atPixel;
|
|
let at = atPixel.unscale(FLOOR_CELL_SIZE);
|
|
this.#floorCenter = atPixel.offset(CENTER);
|
|
this.#ceilingCenter = at.scale(CEILING_CELL_SIZE).offset(CENTER);
|
|
|
|
this.#floorTl = atPixel.offset(new Point(-FLOOR_CELL_SIZE.w / 2, -FLOOR_CELL_SIZE.h / 2))
|
|
.offset(CENTER);
|
|
this.#ceilingTl = at
|
|
.offset(new Point(-0.5, -0.5))
|
|
.scale(CEILING_CELL_SIZE)
|
|
.offset(CENTER)
|
|
.snap(0, 0)
|
|
this.#floorBr = atPixel.offset(new Point(FLOOR_CELL_SIZE.w / 2, FLOOR_CELL_SIZE.h / 2))
|
|
.offset(CENTER);
|
|
this.#ceilingBr = at
|
|
.offset(new Point(0.5, 0.5))
|
|
.scale(CEILING_CELL_SIZE)
|
|
.offset(CENTER)
|
|
.snap(0, 0)
|
|
|
|
// console.log(`floorTl: ${this.#floorTl}`)
|
|
// console.log(`floorBr: ${this.#floorBr}`)
|
|
}
|
|
|
|
get floorRect(): Rect {
|
|
return new Rect(this.#floorTl, this.#floorBr.subtract(this.#floorTl));
|
|
}
|
|
|
|
drawFloor(color: Color) {
|
|
D.fillRect(this.#floorTl, this.#floorBr.subtract(this.#floorTl), color);
|
|
}
|
|
|
|
#drawWallTop(color: Color) {
|
|
let diff = Math.abs(this.#ceilingTl.y - this.#floorTl.y);
|
|
let sign = Math.sign(this.#ceilingTl.y - this.#floorTl.y);
|
|
// console.log(`diff, sign: ${diff}, ${sign}`)
|
|
for (let dy = 0; dy <= diff; dy += 0.25) {
|
|
// 0.25: fudge factor because we get two different lines
|
|
let progress = dy / diff;
|
|
let x0 = Math.floor(lerp(progress, this.#floorTl.x, this.#ceilingTl.x));
|
|
let x1 = Math.ceil(lerp(progress, this.#floorBr.x, this.#ceilingBr.x));
|
|
let y = this.#floorTl.y + sign * dy;
|
|
|
|
if (dy == 0 || dy == diff) {
|
|
// console.log(x0, x1, y);
|
|
}
|
|
D.fillRect(new Point(x0, y - 1), new Size(x1 - x0, 1), color);
|
|
}
|
|
}
|
|
|
|
#drawWallLeft(color: Color) {
|
|
let diff = Math.abs(this.#ceilingTl.x - this.#floorTl.x);
|
|
let sign = Math.sign(this.#ceilingTl.x - this.#floorTl.x);
|
|
// console.log(`diff, sign: ${diff}, ${sign}`)
|
|
for (let dx = 0; dx <= diff; dx += 0.25) {
|
|
// fudge factor because we get two different lines
|
|
let progress = dx / diff;
|
|
let y0 = Math.floor(lerp(progress, this.#floorTl.y, this.#ceilingTl.y));
|
|
let y1 = Math.ceil(lerp(progress, this.#floorBr.y, this.#ceilingBr.y));
|
|
|
|
let x = this.#floorTl.x + sign * dx;
|
|
|
|
D.fillRect(new Point(x, y0), new Size(1, y1 - y0), color);
|
|
}
|
|
}
|
|
|
|
drawWallTop(color: Color) {
|
|
if (this.#atPixel.y > FLOOR_CELL_SIZE.h / 2) {
|
|
return;
|
|
}
|
|
this.#drawWallTop(color);
|
|
}
|
|
|
|
drawWallLeft(color: Color) {
|
|
if (this.#atPixel.x > FLOOR_CELL_SIZE.w / 2) {
|
|
return;
|
|
}
|
|
this.#drawWallLeft(color);
|
|
}
|
|
|
|
drawWallBottom(color: Color) {
|
|
if (this.#atPixel.y < -FLOOR_CELL_SIZE.h / 2) {
|
|
return;
|
|
}
|
|
new GridArt(this.#atPixel.offset(new Point(0, FLOOR_CELL_SIZE.h))).#drawWallTop(color);
|
|
}
|
|
|
|
drawWallRight(color: Color) {
|
|
if (this.#atPixel.x < -FLOOR_CELL_SIZE.w / 2) {
|
|
return;
|
|
}
|
|
new GridArt(this.#atPixel.offset(new Point(FLOOR_CELL_SIZE.w, 0))).#drawWallLeft(color);
|
|
}
|
|
|
|
drawMouldingTop(color: Color) {
|
|
let x0 = this.#ceilingTl.x;
|
|
let y0 = this.#ceilingTl.y - MOULDING_SZ.h;
|
|
let x1 = this.#ceilingBr.x;
|
|
let y1 = this.#ceilingTl.y;
|
|
|
|
D.fillRect(
|
|
new Point(x0, y0),
|
|
new Size(x1 - x0, y1 - y0),
|
|
color
|
|
);
|
|
}
|
|
|
|
drawMouldingTopLeft(color: Color) {
|
|
let x0 = this.#ceilingTl.x - MOULDING_SZ.w;
|
|
let y0 = this.#ceilingTl.y - MOULDING_SZ.h;
|
|
let x1 = this.#ceilingTl.x;
|
|
let y1 = this.#ceilingTl.y;
|
|
|
|
D.fillRect(
|
|
new Point(x0, y0),
|
|
new Size(x1 - x0, y1 - y0),
|
|
color
|
|
);
|
|
}
|
|
|
|
drawMouldingLeft(color: Color) {
|
|
let x0 = this.#ceilingTl.x - MOULDING_SZ.w;
|
|
let y0 = this.#ceilingTl.y;
|
|
let x1 = this.#ceilingTl.x;
|
|
let y1 = this.#ceilingBr.y;
|
|
|
|
D.fillRect(
|
|
new Point(x0, y0),
|
|
new Size(x1 - x0, y1 - y0),
|
|
color
|
|
);
|
|
}
|
|
|
|
drawMouldingTopRight(color: Color) {
|
|
let x0 = this.#ceilingBr.x;
|
|
let y0 = this.#ceilingTl.y - MOULDING_SZ.h;
|
|
let x1 = this.#ceilingBr.x + MOULDING_SZ.w;
|
|
let y1 = this.#ceilingTl.y;
|
|
|
|
D.fillRect(
|
|
new Point(x0, y0),
|
|
new Size(x1 - x0, y1 - y0),
|
|
color
|
|
);
|
|
}
|
|
|
|
drawMouldingBottom(color: Color) {
|
|
let x0 = this.#ceilingTl.x;
|
|
let y0 = this.#ceilingBr.y;
|
|
let x1 = this.#ceilingBr.x;
|
|
let y1 = this.#ceilingBr.y + MOULDING_SZ.h;
|
|
|
|
D.fillRect(
|
|
new Point(x0, y0),
|
|
new Size(x1 - x0, y1 - y0),
|
|
color
|
|
);
|
|
}
|
|
|
|
drawMouldingBottomLeft(color: Color) {
|
|
let x0 = this.#ceilingTl.x - MOULDING_SZ.w;
|
|
let y0 = this.#ceilingBr.y;
|
|
let x1 = this.#ceilingTl.x;
|
|
let y1 = this.#ceilingBr.y + MOULDING_SZ.h;
|
|
|
|
D.fillRect(
|
|
new Point(x0, y0),
|
|
new Size(x1 - x0, y1 - y0),
|
|
color,
|
|
);
|
|
}
|
|
|
|
drawMouldingRight(color: Color) {
|
|
let x0 = this.#ceilingBr.x;
|
|
let y0 = this.#ceilingTl.y;
|
|
let x1 = this.#ceilingBr.x + MOULDING_SZ.w;
|
|
let y1 = this.#ceilingBr.y;
|
|
|
|
D.fillRect(
|
|
new Point(x0, y0),
|
|
new Size(x1 - x0, y1 - y0),
|
|
color
|
|
);
|
|
}
|
|
|
|
drawMouldingBottomRight(color: Color) {
|
|
let x0 = this.#ceilingBr.x;
|
|
let y0 = this.#ceilingBr.y;
|
|
let x1 = this.#ceilingBr.x + MOULDING_SZ.w;
|
|
let y1 = this.#ceilingBr.y + MOULDING_SZ.h;
|
|
|
|
D.fillRect(
|
|
new Point(x0, y0),
|
|
new Size(x1 - x0, y1 - y0),
|
|
color
|
|
);
|
|
}
|
|
|
|
drawCeiling(color: Color) {
|
|
D.fillRect(
|
|
this.#ceilingTl,
|
|
this.#ceilingBr.subtract(this.#ceilingTl),
|
|
color,
|
|
);
|
|
// D.drawRect(this.#ceilingTl, this.#ceilingBr.subtract(this.#ceilingTl), FG_BOLD);
|
|
}
|
|
|
|
project(z: number): Point {
|
|
let z2 = z / HEIGHT_IN_FEET;
|
|
return new Point(
|
|
lerp(z2, this.#floorCenter.x, this.#ceilingCenter.x),
|
|
lerp(z2, this.#floorCenter.y, this.#ceilingCenter.y),
|
|
);
|
|
}
|
|
}
|
|
|
|
let lerp = (amt: number, x: number, y: number) => {
|
|
if (amt <= 0) {
|
|
return x;
|
|
}
|
|
if (amt >= 1) {
|
|
return y;
|
|
}
|
|
return x + (y - x) * amt;
|
|
};
|