diff --git a/src/ui/Renderer2D.js b/src/ui/Renderer2D.js index 88e2d611..dedfa802 100644 --- a/src/ui/Renderer2D.js +++ b/src/ui/Renderer2D.js @@ -23,6 +23,7 @@ import { renderPlaceholder, renderPotatoPlaceholder, renderOverlay, + renderSmallPOverlay, } from './render2Delements'; import PixelPainterControls from '../controls/PixelPainterControls'; @@ -273,7 +274,6 @@ class Renderer2D extends Renderer { const [x, y] = getPixelFromChunkOffset(i, j, offset, canvasSize); - // TODO centerChunk is scaled! const [canX, canY] = this.centerChunk .map((z) => (z + 0.5) * TILE_SIZE - canvasSize / 2); const { width: canvasWidth, height: canvasHeight } = this.canvas; @@ -423,10 +423,12 @@ class Renderer2D extends Renderer { } context.restore(); // TODO conditions - renderOverlay( - this.canvas, chunkPosition, canvasSize, scale, - this.tiledScale, this.scaleThreshold, - ); + if (false) { + renderOverlay( + state, this.canvas, chunkPosition, scale, + this.tiledScale, this.scaleThreshold, + ); + } } @@ -552,6 +554,11 @@ class Renderer2D extends Renderer { ); } + // TODO conditions + if (viewscale >= 5) { + renderSmallPOverlay(viewport, _view, viewscale); + } + if (showGrid && viewscale >= 8) { renderGrid(state, viewport, _view, viewscale, isLightGrid); } diff --git a/src/ui/Template.js b/src/ui/Template.js index a1a390e6..7ddb8195 100644 --- a/src/ui/Template.js +++ b/src/ui/Template.js @@ -19,11 +19,46 @@ class Template { height; // if image is loaded ready = false; + // small pixels image + #imageSmall; constructor(imageId) { this.id = imageId; } + get imageSmall() { + if (!this.#imageSmall) { + const imgData = this.image.getContext('2d').getImageData( + 0, 0, this.width, this.height, + ); + const imageSmall = document.createElement('canvas'); + imageSmall.width = this.width * 3; + imageSmall.height = this.height * 3; + const targetContext = imageSmall.getContext('2d'); + const targetData = targetContext.getImageData( + 0, 0, imageSmall.width, imageSmall.height, + ); + + let c = 0; + let o = targetData.width * 4 + 4; + while (c < imgData.data.length) { + for (let r = 0; r < imgData.width; r += 1) { + targetData.data[o] = imgData.data[c]; + targetData.data[++o] = imgData.data[++c]; + targetData.data[++o] = imgData.data[++c]; + targetData.data[++o] = imgData.data[++c]; + o += 1 + 2 * 4; + c += 1; + } + o += targetData.width * 4 * 2; + } + targetContext.putImageData(targetData, 0, 0); + this.#imageSmall = imageSmall; + } + + return this.#imageSmall; + } + async arrayBuffer() { return canvasToBuffer(this.image); } diff --git a/src/ui/render2Delements.js b/src/ui/render2Delements.js index b15bb7a5..1b72c940 100644 --- a/src/ui/render2Delements.js +++ b/src/ui/render2Delements.js @@ -52,8 +52,7 @@ export function renderPotatoPlaceholder( ) { const viewportCtx = $viewport.getContext('2d'); - const { hover } = state.canvas; - const { palette, selectedColor } = state.canvas; + const { palette, selectedColor, hover } = state.canvas; const [sx, sy] = worldToScreen(view, scale, $viewport, hover); @@ -107,13 +106,14 @@ export function renderGrid( * Overlay draws onto offscreen canvas, so its doing weirder math */ export function renderOverlay( + state, $canvas, centerChunk, - canvasSize, scale, tiledScale, scaleThreshold, ) { + const { canvasSize } = state.canvas; // world coordinates of center of center chunk const [x, y] = centerChunk .map((z) => z * TILE_SIZE / tiledScale @@ -138,6 +138,7 @@ export function renderOverlay( for (const template of templates) { const image = templateLoader.getTemplateSync(template.imageId); if (!image) continue; + context.drawImage(image, template.x - x + width / 2 / offscreenScale, template.y - y + height / 2 / offscreenScale, @@ -145,3 +146,38 @@ export function renderOverlay( } context.restore(); } + +/* + * Small pixel overlay draws into viewport, because it needs + * high scale values + */ +export function renderSmallPOverlay( + $viewport, + view, + scale, +) { + const [x, y] = view; + const { width, height } = $viewport; + const horizontalRadius = width / 2 / scale; + const verticalRadius = height / 2 / scale; + const templates = templateLoader.getTemplatesInView( + x, y, horizontalRadius, verticalRadius, + ); + + if (!templates.length) return; + const context = $viewport.getContext('2d'); + if (!context) return; + + const relScale = scale / 3; + context.save(); + context.scale(relScale, relScale); + for (const template of templates) { + const image = templateLoader.getSmallTemplateSync(template.imageId); + if (!image) continue; + context.drawImage(image, + (template.x - x) * 3 + width / 2 / relScale, + (template.y - y) * 3 + height / 2 / relScale, + ); + } + context.restore(); +} diff --git a/src/ui/templateLoader.js b/src/ui/templateLoader.js index f4c99089..aee6e53d 100644 --- a/src/ui/templateLoader.js +++ b/src/ui/templateLoader.js @@ -63,6 +63,19 @@ class TemplateLoader { return null; } + getSmallTemplateSync(id) { + if (!this.ready) { + return null; + } + const template = this.#templates.get(id); + if (template) { + return template.imageSmall; + } + // TODO some store action when available + this.loadExistingTemplate(id); + return null; + } + getTemplatesInView(x, y, horizontalRadius, verticalRadius) { const topX = x - horizontalRadius; const topY = y - verticalRadius;