|
|
@ -60,6 +60,7 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
this.screenBG = [] |
|
|
|
this.screenBG = [] |
|
|
|
this.screenAttrs = [] |
|
|
|
this.screenAttrs = [] |
|
|
|
this.screenSelection = [] |
|
|
|
this.screenSelection = [] |
|
|
|
|
|
|
|
this.screenLines = [] |
|
|
|
this.cursor = {} |
|
|
|
this.cursor = {} |
|
|
|
this.reverseVideo = false |
|
|
|
this.reverseVideo = false |
|
|
|
this.hasBlinkingCells = false |
|
|
|
this.hasBlinkingCells = false |
|
|
@ -96,6 +97,7 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
this.drawnScreenFG = [] |
|
|
|
this.drawnScreenFG = [] |
|
|
|
this.drawnScreenBG = [] |
|
|
|
this.drawnScreenBG = [] |
|
|
|
this.drawnScreenAttrs = [] |
|
|
|
this.drawnScreenAttrs = [] |
|
|
|
|
|
|
|
this.drawnScreenLines = [] |
|
|
|
this.drawnCursor = [-1, -1, '', false] |
|
|
|
this.drawnCursor = [-1, -1, '', false] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -209,6 +211,9 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
drawBackground ({ x, y, cellWidth, cellHeight, bg, isDefaultBG }) { |
|
|
|
drawBackground ({ x, y, cellWidth, cellHeight, bg, isDefaultBG }) { |
|
|
|
const { ctx, width, height, padding } = this |
|
|
|
const { ctx, width, height, padding } = this |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// is a double-width/double-height line
|
|
|
|
|
|
|
|
if (this.screenLines[y] & 0b001) cellWidth *= 2 |
|
|
|
|
|
|
|
|
|
|
|
ctx.fillStyle = this.getColor(bg) |
|
|
|
ctx.fillStyle = this.getColor(bg) |
|
|
|
let screenX = x * cellWidth + padding |
|
|
|
let screenX = x * cellWidth + padding |
|
|
|
let screenY = y * cellHeight + padding |
|
|
|
let screenY = y * cellHeight + padding |
|
|
@ -276,6 +281,39 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
let screenX = x * cellWidth + padding |
|
|
|
let screenX = x * cellWidth + padding |
|
|
|
let screenY = y * cellHeight + padding |
|
|
|
let screenY = y * cellHeight + padding |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const dblWidth = this.screenLines[y] & 0b001 |
|
|
|
|
|
|
|
const dblHeightTop = this.screenLines[y] & 0b010 |
|
|
|
|
|
|
|
const dblHeightBot = this.screenLines[y] & 0b100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.screenLines[y]) { |
|
|
|
|
|
|
|
// is a double-width/double-height line
|
|
|
|
|
|
|
|
if (dblWidth) cellWidth *= 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ctx.save() |
|
|
|
|
|
|
|
ctx.translate(padding, screenY + 0.5 * cellHeight) |
|
|
|
|
|
|
|
if (dblWidth) ctx.scale(2, 1) |
|
|
|
|
|
|
|
if (dblHeightTop) { |
|
|
|
|
|
|
|
// top half
|
|
|
|
|
|
|
|
ctx.scale(1, 2) |
|
|
|
|
|
|
|
ctx.translate(0, cellHeight / 4) |
|
|
|
|
|
|
|
} else if (dblHeightBot) { |
|
|
|
|
|
|
|
// bottom half
|
|
|
|
|
|
|
|
ctx.scale(1, 2) |
|
|
|
|
|
|
|
ctx.translate(0, -cellHeight / 4) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
ctx.translate(-padding, -screenY - 0.5 * cellHeight) |
|
|
|
|
|
|
|
if (dblWidth) ctx.translate(-cellWidth / 4, 0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (dblHeightBot || dblHeightTop) { |
|
|
|
|
|
|
|
// characters overflow -- needs clipping
|
|
|
|
|
|
|
|
// TODO: clipping is really expensive
|
|
|
|
|
|
|
|
ctx.beginPath() |
|
|
|
|
|
|
|
if (dblHeightTop) ctx.rect(screenX, screenY, cellWidth, cellHeight / 2) |
|
|
|
|
|
|
|
else ctx.rect(screenX, screenY + cellHeight / 2, cellWidth, cellHeight / 2) |
|
|
|
|
|
|
|
ctx.clip() |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let codePoint = text.codePointAt(0) |
|
|
|
let codePoint = text.codePointAt(0) |
|
|
|
if (codePoint >= 0x2580 && codePoint <= 0x259F) { |
|
|
|
if (codePoint >= 0x2580 && codePoint <= 0x259F) { |
|
|
|
// block elements
|
|
|
|
// block elements
|
|
|
@ -450,6 +488,8 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
ctx.stroke() |
|
|
|
ctx.stroke() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.screenLines[y]) ctx.restore() |
|
|
|
|
|
|
|
|
|
|
|
ctx.globalAlpha = 1 |
|
|
|
ctx.globalAlpha = 1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -558,6 +598,7 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
fg !== this.drawnScreenFG[cell] || // foreground updated, and this cell has text
|
|
|
|
fg !== this.drawnScreenFG[cell] || // foreground updated, and this cell has text
|
|
|
|
bg !== this.drawnScreenBG[cell] || // background updated
|
|
|
|
bg !== this.drawnScreenBG[cell] || // background updated
|
|
|
|
attrs !== this.drawnScreenAttrs[cell] || // attributes updated
|
|
|
|
attrs !== this.drawnScreenAttrs[cell] || // attributes updated
|
|
|
|
|
|
|
|
this.screenLines[y] !== this.drawnScreenLines[y] || // line updated
|
|
|
|
// TODO: fix artifacts or keep this hack:
|
|
|
|
// TODO: fix artifacts or keep this hack:
|
|
|
|
isCursor || wasCursor || // cursor blink/position updated
|
|
|
|
isCursor || wasCursor || // cursor blink/position updated
|
|
|
|
(isCursor && this.cursor.style !== this.drawnCursor[2]) || // cursor style updated
|
|
|
|
(isCursor && this.cursor.style !== this.drawnCursor[2]) || // cursor style updated
|
|
|
@ -570,6 +611,9 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
updateMap.set(cell, didUpdate) |
|
|
|
updateMap.set(cell, didUpdate) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// set drawn screen lines
|
|
|
|
|
|
|
|
this.drawnScreenLines = this.screenLines.slice() |
|
|
|
|
|
|
|
|
|
|
|
let debugFilledUpdates = [] |
|
|
|
let debugFilledUpdates = [] |
|
|
|
|
|
|
|
|
|
|
|
if (this.graphics >= 1) { |
|
|
|
if (this.graphics >= 1) { |
|
|
@ -613,7 +657,10 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
// update this cell if:
|
|
|
|
// update this cell if:
|
|
|
|
// - the adjacent cell updated (For now, this'll always be true because characters can be slightly larger than they say they are)
|
|
|
|
// - the adjacent cell updated (For now, this'll always be true because characters can be slightly larger than they say they are)
|
|
|
|
// - the adjacent cell updated and this cell or the adjacent cell is wide
|
|
|
|
// - the adjacent cell updated and this cell or the adjacent cell is wide
|
|
|
|
if (updateMap.get(adjacentCell) && (this.graphics < 2 || isWideCell || isTextWide(this.screen[adjacentCell]))) { |
|
|
|
// - this or the adjacent cell is not double-sized
|
|
|
|
|
|
|
|
if (updateMap.get(adjacentCell) && |
|
|
|
|
|
|
|
(this.graphics < 2 || isWideCell || isTextWide(this.screen[adjacentCell])) && |
|
|
|
|
|
|
|
(!this.screenLines[Math.floor(cell / this.width)] && !this.screenLines[Math.floor(adjacentCell / this.width)])) { |
|
|
|
adjacentDidUpdate = true |
|
|
|
adjacentDidUpdate = true |
|
|
|
|
|
|
|
|
|
|
|
if (this.getAdjacentCells(cell, 1).includes(adjacentCell)) { |
|
|
|
if (this.getAdjacentCells(cell, 1).includes(adjacentCell)) { |
|
|
@ -680,8 +727,6 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
i++ |
|
|
|
i++ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
console.log(regions) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ctx.save() |
|
|
|
ctx.save() |
|
|
|
ctx.beginPath() |
|
|
|
ctx.beginPath() |
|
|
|
for (let region of regions) { |
|
|
|
for (let region of regions) { |
|
|
@ -763,17 +808,22 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
|
|
|
|
|
|
|
|
let cursorX = x |
|
|
|
let cursorX = x |
|
|
|
let cursorY = y |
|
|
|
let cursorY = y |
|
|
|
|
|
|
|
let cursorWidth = cellWidth // JS doesn't allow same-name assignment
|
|
|
|
|
|
|
|
|
|
|
|
if (this.cursor.hanging) { |
|
|
|
if (this.cursor.hanging) { |
|
|
|
// draw hanging cursor in the margin
|
|
|
|
// draw hanging cursor in the margin
|
|
|
|
cursorX += 1 |
|
|
|
cursorX += 1 |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let screenX = cursorX * cellWidth + this.padding |
|
|
|
// double-width lines
|
|
|
|
|
|
|
|
if (this.screenLines[cursorY] & 0b001) cursorWidth *= 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let screenX = cursorX * cursorWidth + this.padding |
|
|
|
let screenY = cursorY * cellHeight + this.padding |
|
|
|
let screenY = cursorY * cellHeight + this.padding |
|
|
|
|
|
|
|
|
|
|
|
if (this.cursor.style === 'block') { |
|
|
|
if (this.cursor.style === 'block') { |
|
|
|
// block
|
|
|
|
// block
|
|
|
|
ctx.rect(screenX, screenY, cellWidth, cellHeight) |
|
|
|
ctx.rect(screenX, screenY, cursorWidth, cellHeight) |
|
|
|
} else if (this.cursor.style === 'bar') { |
|
|
|
} else if (this.cursor.style === 'bar') { |
|
|
|
// vertical bar
|
|
|
|
// vertical bar
|
|
|
|
let barWidth = 2 |
|
|
|
let barWidth = 2 |
|
|
@ -781,7 +831,7 @@ module.exports = class CanvasRenderer extends EventEmitter { |
|
|
|
} else if (this.cursor.style === 'line') { |
|
|
|
} else if (this.cursor.style === 'line') { |
|
|
|
// underline
|
|
|
|
// underline
|
|
|
|
let lineHeight = 2 |
|
|
|
let lineHeight = 2 |
|
|
|
ctx.rect(screenX, screenY + charSize.height, cellWidth, lineHeight) |
|
|
|
ctx.rect(screenX, screenY + charSize.height, cursorWidth, lineHeight) |
|
|
|
} |
|
|
|
} |
|
|
|
ctx.clip() |
|
|
|
ctx.clip() |
|
|
|
|
|
|
|
|
|
|
|