mirror of
https://github.com/SwingTheVine/Wplace-BlueMarble.git
synced 2026-03-11 17:15:38 +00:00
Removed color filter (2)
This commit is contained in:
parent
c40c0589db
commit
083462d0f6
7 changed files with 43 additions and 327 deletions
4
dist/BlueMarble.user.js
vendored
4
dist/BlueMarble.user.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -51,7 +51,7 @@
|
|||
<a href="https://discord.gg/tpeBPy46hf" target="_blank" rel="noopener noreferrer"><img alt="Contact Me" src="https://img.shields.io/badge/Contact_Me-gray?style=flat&logo=Discord&logoColor=white&logoSize=auto&labelColor=cornflowerblue"></a>
|
||||
<a href="https://bluemarble.lol/" target="_blank" rel="noopener noreferrer"><img alt="Blue Marble Website" src="https://img.shields.io/badge/Blue_Marble_Website-crqch-blue?style=flat&logo=globe&logoColor=white"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="WakaTime" src="https://img.shields.io/badge/Coding_Time-111hrs_12mins-blue?style=flat&logo=wakatime&logoColor=black&logoSize=auto&labelColor=white"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-498-black?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Patches" src="https://img.shields.io/badge/Total_Patches-501-black?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Lines of Code" src="https://img.shields.io/badge/Lines_Of_Code-498-blue?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Total Comments" src="https://img.shields.io/badge/Lines_Of_Comments-498-blue?style=flat"></a>
|
||||
<a href="" target="_blank" rel="noopener noreferrer"><img alt="Compression" src="https://img.shields.io/badge/Compression-70.19%25-blue"></a>
|
||||
|
|
|
|||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.88.0",
|
||||
"version": "0.88.3",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.88.0",
|
||||
"version": "0.88.3",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"jsdoc": "^4.0.5",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "wplace-bluemarble",
|
||||
"version": "0.88.0",
|
||||
"version": "0.88.3",
|
||||
"type": "module",
|
||||
"homepage": "https://bluemarble.lol/",
|
||||
"repository": {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// ==UserScript==
|
||||
// @name Blue Marble
|
||||
// @namespace https://github.com/SwingTheVine/
|
||||
// @version 0.88.0
|
||||
// @version 0.88.3
|
||||
// @description A userscript to automate and/or enhance the user experience on Wplace.live. Make sure to comply with the site's Terms of Service, and rules! This script is not affiliated with Wplace.live in any way, use at your own risk. This script is not affiliated with TamperMonkey. The author of this userscript is not responsible for any damages, issues, loss of data, or punishment that may occur as a result of using this script. This script is provided "as is" under the MPL-2.0 license. The "Blue Marble" icon is licensed under CC0 1.0 Universal (CC0 1.0) Public Domain Dedication. The image is owned by NASA.
|
||||
// @author SwingTheVine
|
||||
// @license MPL-2.0
|
||||
|
|
|
|||
|
|
@ -498,7 +498,7 @@ function buildOverlayMain() {
|
|||
}
|
||||
}
|
||||
).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-tx', 'placeholder': 'Tl X', 'min': 0, 'max': 2047, 'step': 1, 'required': true, 'value': (savedCoords.tx ?? '')}, (instance, input) => {
|
||||
.addInput({'type': 'number', 'id': 'bm-input-tx', 'placeholder': 'Tl X', 'min': 0, 'max': 2047, 'step': 1, 'required': true}, (instance, input) => {
|
||||
//if a paste happens on tx, split and format it into other coordinates if possible
|
||||
input.addEventListener("paste", (event) => {
|
||||
let splitText = (event.clipboardData || window.clipboardData).getData("text").split(" ").filter(n => n).map(Number).filter(n => !isNaN(n)); //split and filter all Non Numbers
|
||||
|
|
@ -519,17 +519,17 @@ function buildOverlayMain() {
|
|||
input.addEventListener('input', handler);
|
||||
input.addEventListener('change', handler);
|
||||
}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-ty', 'placeholder': 'Tl Y', 'min': 0, 'max': 2047, 'step': 1, 'required': true, 'value': (savedCoords.ty ?? '')}, (instance, input) => {
|
||||
.addInput({'type': 'number', 'id': 'bm-input-ty', 'placeholder': 'Tl Y', 'min': 0, 'max': 2047, 'step': 1, 'required': true}, (instance, input) => {
|
||||
const handler = () => persistCoords();
|
||||
input.addEventListener('input', handler);
|
||||
input.addEventListener('change', handler);
|
||||
}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-px', 'placeholder': 'Px X', 'min': 0, 'max': 2047, 'step': 1, 'required': true, 'value': (savedCoords.px ?? '')}, (instance, input) => {
|
||||
.addInput({'type': 'number', 'id': 'bm-input-px', 'placeholder': 'Px X', 'min': 0, 'max': 2047, 'step': 1, 'required': true}, (instance, input) => {
|
||||
const handler = () => persistCoords();
|
||||
input.addEventListener('input', handler);
|
||||
input.addEventListener('change', handler);
|
||||
}).buildElement()
|
||||
.addInput({'type': 'number', 'id': 'bm-input-py', 'placeholder': 'Px Y', 'min': 0, 'max': 2047, 'step': 1, 'required': true, 'value': (savedCoords.py ?? '')}, (instance, input) => {
|
||||
.addInput({'type': 'number', 'id': 'bm-input-py', 'placeholder': 'Px Y', 'min': 0, 'max': 2047, 'step': 1, 'required': true}, (instance, input) => {
|
||||
const handler = () => persistCoords();
|
||||
input.addEventListener('input', handler);
|
||||
input.addEventListener('change', handler);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ export default class TemplateManager {
|
|||
this.templatesArray = []; // All Template instnaces currently loaded (Template)
|
||||
this.templatesJSON = null; // All templates currently loaded (JSON)
|
||||
this.templatesShouldBeDrawn = true; // Should ALL templates be drawn to the canvas?
|
||||
this.tileProgress = new Map(); // Tracks per-tile progress stats {painted, required, wrong}
|
||||
}
|
||||
|
||||
/** Retrieves the pixel art canvas.
|
||||
|
|
@ -144,32 +143,17 @@ export default class TemplateManager {
|
|||
|
||||
// Appends a child into the templates object
|
||||
// The child's name is the number of templates already in the list (sort order) plus the encoded player ID
|
||||
const storageKey = `${template.sortID} ${template.authorID}`;
|
||||
template.storageKey = storageKey;
|
||||
this.templatesJSON.templates[storageKey] = {
|
||||
this.templatesJSON.templates[`${template.sortID} ${template.authorID}`] = {
|
||||
"name": template.displayName, // Display name of template
|
||||
"coords": coords.join(', '), // The coords of the template
|
||||
"enabled": true,
|
||||
"tiles": templateTilesBuffers, // Stores the chunked tile buffers
|
||||
"palette": template.colorPalette // Persist palette and enabled flags
|
||||
"tiles": templateTilesBuffers // Stores the chunked tile buffers
|
||||
};
|
||||
|
||||
this.templatesArray = []; // Remove this to enable multiple templates (2/2)
|
||||
this.templatesArray.push(template); // Pushes the Template object instance to the Template Array
|
||||
|
||||
// ==================== PIXEL COUNT DISPLAY SYSTEM ====================
|
||||
// Display pixel count statistics with internationalized number formatting
|
||||
// This provides immediate feedback to users about template complexity and size
|
||||
const pixelCountFormatted = new Intl.NumberFormat().format(template.pixelCount);
|
||||
this.overlay.handleDisplayStatus(`Template created at ${coords.join(', ')}! Total pixels: ${pixelCountFormatted}`);
|
||||
|
||||
// Ensure color filter UI is visible when a template is created
|
||||
try {
|
||||
const colorUI = document.querySelector('#bm-contain-colorfilter');
|
||||
if (colorUI) { colorUI.style.display = ''; }
|
||||
// Deferred palette list rendering; actual DOM is built in main via helper
|
||||
window.postMessage({ source: 'blue-marble', bmEvent: 'bm-rebuild-color-list' }, '*');
|
||||
} catch (_) { /* no-op */ }
|
||||
this.overlay.handleDisplayStatus(`Template created at ${coords.join(', ')}!`);
|
||||
|
||||
console.log(Object.keys(this.templatesJSON.templates).length);
|
||||
console.log(this.templatesJSON);
|
||||
|
|
@ -235,18 +219,6 @@ export default class TemplateManager {
|
|||
|
||||
console.log(templateArray);
|
||||
|
||||
// Early exit if none of the active templates touch this tile
|
||||
const anyTouches = templateArray.some(t => {
|
||||
if (!t?.chunked) { return false; }
|
||||
// Fast path via recorded tile prefixes if available
|
||||
if (t.tilePrefixes && t.tilePrefixes.size > 0) {
|
||||
return t.tilePrefixes.has(tileCoords);
|
||||
}
|
||||
// Fallback: scan chunked keys
|
||||
return Object.keys(t.chunked).some(k => k.startsWith(tileCoords));
|
||||
});
|
||||
if (!anyTouches) { return tileBlob; }
|
||||
|
||||
// Retrieves the relavent template tile blobs
|
||||
const templatesToDraw = templateArray
|
||||
.map(template => {
|
||||
|
|
@ -277,10 +249,31 @@ export default class TemplateManager {
|
|||
const templateCount = templatesToDraw?.length || 0; // Number of templates to draw on this tile
|
||||
console.log(`templateCount = ${templateCount}`);
|
||||
|
||||
// We'll compute per-tile painted/wrong/required counts when templates exist for this tile
|
||||
let paintedCount = 0;
|
||||
let wrongCount = 0;
|
||||
let requiredCount = 0;
|
||||
if (templateCount > 0) {
|
||||
|
||||
// Calculate total pixel count for templates actively being displayed in this tile
|
||||
const totalPixels = templateArray
|
||||
.filter(template => {
|
||||
// Filter templates to include only those with tiles matching current coordinates
|
||||
// This ensures we count pixels only for templates actually being rendered
|
||||
const matchingTiles = Object.keys(template.chunked).filter(tile =>
|
||||
tile.startsWith(tileCoords)
|
||||
);
|
||||
return matchingTiles.length > 0;
|
||||
})
|
||||
.reduce((sum, template) => sum + (template.pixelCount || 0), 0);
|
||||
|
||||
// Format pixel count with locale-appropriate thousands separators for better readability
|
||||
// Examples: "1,234,567" (US), "1.234.567" (DE), "1 234 567" (FR)
|
||||
const pixelCountFormatted = new Intl.NumberFormat().format(totalPixels);
|
||||
|
||||
// Display status information about the templates being rendered
|
||||
this.overlay.handleDisplayStatus(
|
||||
`Displaying ${templateCount} template${templateCount == 1 ? '' : 's'}.\nTotal pixels: ${pixelCountFormatted}`
|
||||
);
|
||||
} else {
|
||||
this.overlay.handleDisplayStatus(`Displaying ${templateCount} templates.`);
|
||||
}
|
||||
|
||||
const tileBitmap = await createImageBitmap(tileBlob);
|
||||
|
||||
|
|
@ -297,234 +290,16 @@ export default class TemplateManager {
|
|||
context.clearRect(0, 0, drawSize, drawSize); // Draws transparent background
|
||||
context.drawImage(tileBitmap, 0, 0, drawSize, drawSize);
|
||||
|
||||
// Grab a snapshot of the tile pixels BEFORE we draw any template overlays
|
||||
let tilePixels = null;
|
||||
try {
|
||||
tilePixels = context.getImageData(0, 0, drawSize, drawSize).data;
|
||||
} catch (_) {
|
||||
// If reading fails for any reason, we will skip stats
|
||||
}
|
||||
|
||||
// For each template in this tile, draw them.
|
||||
for (const template of templatesToDraw) {
|
||||
console.log(`Template:`);
|
||||
console.log(template);
|
||||
|
||||
// Compute stats by sampling template center pixels against tile pixels,
|
||||
// honoring color enable/disable from the active template's palette
|
||||
if (tilePixels) {
|
||||
try {
|
||||
|
||||
const tempWidth = template.bitmap.width;
|
||||
const tempHeight = template.bitmap.height;
|
||||
const tempCanvas = new OffscreenCanvas(tempWidth, tempHeight);
|
||||
const tempContext = tempCanvas.getContext('2d', { willReadFrequently: true });
|
||||
tempContext.imageSmoothingEnabled = false;
|
||||
tempContext.clearRect(0, 0, tempWidth, tempHeight);
|
||||
tempContext.drawImage(template.bitmap, 0, 0);
|
||||
const tImg = tempContext.getImageData(0, 0, tempWidth, tempHeight);
|
||||
const tData = tImg.data; // Tile Data, Template Data, or Temp Data????
|
||||
// Draws the each template on the tile based on it's relative position
|
||||
context.drawImage(template.bitmap, Number(template.pixelCoords[0]) * this.drawMult, Number(template.pixelCoords[1]) * this.drawMult);
|
||||
|
||||
const offsetX = Number(template.pixelCoords[0]) * this.drawMult;
|
||||
const offsetY = Number(template.pixelCoords[1]) * this.drawMult;
|
||||
|
||||
// Loops over all pixels in the template
|
||||
// Assigns each pixel a color (if center pixel)
|
||||
for (let y = 0; y < tempHeight; y++) {
|
||||
for (let x = 0; x < tempWidth; x++) {
|
||||
// Purpose: Count which pixels are painted correctly???
|
||||
|
||||
// Only evaluate the center pixel of each shread block
|
||||
// Skip if not the center pixel of the shread block
|
||||
if ((x % this.drawMult) !== 1 || (y % this.drawMult) !== 1) { continue; }
|
||||
|
||||
const gx = x + offsetX;
|
||||
const gy = y + offsetY;
|
||||
|
||||
// IF the pixel is out of bounds of the template, OR if the pixel is outside of the tile, then skip the pixel
|
||||
if (gx < 0 || gy < 0 || gx >= drawSize || gy >= drawSize) { continue; }
|
||||
|
||||
const templatePixelCenter = (y * tempWidth + x) * 4; // Shread block center pixel
|
||||
const templatePixelCenterRed = tData[templatePixelCenter]; // Shread block's center pixel's RED value
|
||||
const templatePixelCenterGreen = tData[templatePixelCenter + 1]; // Shread block's center pixel's GREEN value
|
||||
const templatePixelCenterBlue = tData[templatePixelCenter + 2]; // Shread block's center pixel's BLUE value
|
||||
const templatePixelCenterAlpha = tData[templatePixelCenter + 3]; // Shread block's center pixel's ALPHA value
|
||||
|
||||
// Possibly needs to be removed
|
||||
// Handle template transparent pixel (alpha < 64): wrong if board has any site palette color here
|
||||
// If the alpha of the center pixel is less than 64...
|
||||
if (templatePixelCenterAlpha < 64) {
|
||||
try {
|
||||
const activeTemplate = this.templatesArray?.[0];
|
||||
const tileIdx = (gy * drawSize + gx) * 4;
|
||||
const pr = tilePixels[tileIdx];
|
||||
const pg = tilePixels[tileIdx + 1];
|
||||
const pb = tilePixels[tileIdx + 2];
|
||||
const pa = tilePixels[tileIdx + 3];
|
||||
|
||||
const key = activeTemplate.allowedColorsSet.has(`${pr},${pg},${pb}`) ? `${pr},${pg},${pb}` : 'other';
|
||||
|
||||
const isSiteColor = activeTemplate?.allowedColorsSet ? activeTemplate.allowedColorsSet.has(key) : false;
|
||||
|
||||
// IF the alpha of the center pixel that is placed on the canvas is greater than or equal to 64, AND the pixel is a Wplace palette color, then it is incorrect.
|
||||
if (pa >= 64 && isSiteColor) {
|
||||
wrongCount++;
|
||||
}
|
||||
} catch (ignored) {}
|
||||
|
||||
continue; // Continue to the next pixel
|
||||
}
|
||||
|
||||
// Treat #deface as Transparent palette color (required and paintable)
|
||||
// Ignore non-palette colors (match against allowed set when available) for counting required template pixels
|
||||
// try {
|
||||
|
||||
// const activeTemplate = this.templatesArray?.[0]; // Get the first template
|
||||
|
||||
// // IF the stored palette data exists, AND the pixel is not in the allowed palette
|
||||
// if (activeTemplate?.allowedColorsSet && !activeTemplate.allowedColorsSet.has(`${templatePixelCenterRed},${templatePixelCenterGreen},${templatePixelCenterBlue}`)) {
|
||||
|
||||
// continue; // Skip this pixel if it is not in the allowed palette
|
||||
// }
|
||||
// } catch (ignored) {}
|
||||
|
||||
requiredCount++;
|
||||
|
||||
// Strict center-pixel matching. Treat transparent tile pixels as unpainted (not wrong)
|
||||
const realPixelCenter = (gy * drawSize + gx) * 4;
|
||||
const realPixelRed = tilePixels[realPixelCenter];
|
||||
const realPixelCenterGreen = tilePixels[realPixelCenter + 1];
|
||||
const realPixelCenterBlue = tilePixels[realPixelCenter + 2];
|
||||
const realPixelCenterAlpha = tilePixels[realPixelCenter + 3];
|
||||
|
||||
// IF the alpha of the pixel is less than 64...
|
||||
if (realPixelCenterAlpha < 64) {
|
||||
// Unpainted -> neither painted nor wrong
|
||||
|
||||
// ELSE IF the pixel matches the template center pixel color
|
||||
} else if (realPixelRed === templatePixelCenterRed && realPixelCenterGreen === templatePixelCenterGreen && realPixelCenterBlue === templatePixelCenterBlue) {
|
||||
paintedCount++; // ...the pixel is painted correctly
|
||||
} else {
|
||||
wrongCount++; // ...the pixel is NOT painted correctly
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (exception) {
|
||||
console.warn('Failed to compute per-tile painted/wrong stats:', exception);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the template overlay for visual guidance, honoring color filter
|
||||
try {
|
||||
|
||||
const activeTemplate = this.templatesArray?.[0]; // Get the first template
|
||||
const palette = activeTemplate?.colorPalette || {}; // Obtain the color palette of the template
|
||||
const hasDisabled = Object.values(palette).some(v => v?.enabled === false); // Check if any color is disabled
|
||||
|
||||
// If none of the template colors are disabled, then draw the image normally
|
||||
if (!hasDisabled) {
|
||||
context.drawImage(template.bitmap, Number(template.pixelCoords[0]) * this.drawMult, Number(template.pixelCoords[1]) * this.drawMult);
|
||||
} else {
|
||||
// ELSE we need to apply the color filter
|
||||
|
||||
console.log('Applying color filter...');
|
||||
|
||||
const tempW = template.bitmap.width;
|
||||
const tempH = template.bitmap.height;
|
||||
|
||||
const filterCanvas = new OffscreenCanvas(tempW, tempH);
|
||||
const filterCtx = filterCanvas.getContext('2d', { willReadFrequently: true });
|
||||
filterCtx.imageSmoothingEnabled = false; // Nearest neighbor
|
||||
filterCtx.clearRect(0, 0, tempW, tempH);
|
||||
filterCtx.drawImage(template.bitmap, 0, 0);
|
||||
|
||||
const img = filterCtx.getImageData(0, 0, tempW, tempH);
|
||||
const data = img.data;
|
||||
|
||||
// For every pixel...
|
||||
for (let y = 0; y < tempH; y++) {
|
||||
for (let x = 0; x < tempW; x++) {
|
||||
|
||||
// If this pixel is NOT the center pixel, then skip the pixel
|
||||
if ((x % this.drawMult) !== 1 || (y % this.drawMult) !== 1) { continue; }
|
||||
|
||||
const idx = (y * tempW + x) * 4;
|
||||
const r = data[idx];
|
||||
const g = data[idx + 1];
|
||||
const b = data[idx + 2];
|
||||
const a = data[idx + 3];
|
||||
|
||||
if (a < 1) { continue; }
|
||||
|
||||
let key = activeTemplate.allowedColorsSet.has(`${r},${g},${b}`) ? `${r},${g},${b}` : 'other';
|
||||
|
||||
// Hide if color is not in allowed palette or explicitly disabled
|
||||
const inWplacePalette = activeTemplate?.allowedColorsSet ? activeTemplate.allowedColorsSet.has(key) : true;
|
||||
|
||||
// if (inWplacePalette) {
|
||||
// key = 'other'; // Map all non-palette colors to "other"
|
||||
// console.log('Added color to other');
|
||||
// }
|
||||
|
||||
const isPaletteColorEnabled = palette?.[key]?.enabled !== false;
|
||||
if (!inWplacePalette || !isPaletteColorEnabled) {
|
||||
data[idx + 3] = 0; // hide disabled color center pixel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draws the template with somes colors disabled
|
||||
filterCtx.putImageData(img, 0, 0);
|
||||
context.drawImage(filterCanvas, Number(template.pixelCoords[0]) * this.drawMult, Number(template.pixelCoords[1]) * this.drawMult);
|
||||
}
|
||||
} catch (exception) {
|
||||
|
||||
// If filtering fails, we can log the error or handle it accordingly
|
||||
console.warn('Failed to apply color filter:', exception);
|
||||
|
||||
// Fallback to drawing raw bitmap if filtering fails
|
||||
context.drawImage(template.bitmap, Number(template.pixelCoords[0]) * this.drawMult, Number(template.pixelCoords[1]) * this.drawMult);
|
||||
}
|
||||
return await canvas.convertToBlob({ type: 'image/png' });
|
||||
}
|
||||
|
||||
// Save per-tile stats and compute global aggregates across all processed tiles
|
||||
if (templateCount > 0) {
|
||||
const tileKey = tileCoords; // already padded string "xxxx,yyyy"
|
||||
this.tileProgress.set(tileKey, {
|
||||
painted: paintedCount,
|
||||
required: requiredCount,
|
||||
wrong: wrongCount,
|
||||
});
|
||||
|
||||
// Aggregate painted/wrong across tiles we've processed
|
||||
let aggPainted = 0;
|
||||
let aggRequiredTiles = 0;
|
||||
let aggWrong = 0;
|
||||
for (const stats of this.tileProgress.values()) {
|
||||
aggPainted += stats.painted || 0;
|
||||
aggRequiredTiles += stats.required || 0;
|
||||
aggWrong += stats.wrong || 0;
|
||||
}
|
||||
|
||||
// Determine total required across all templates
|
||||
// Prefer precomputed per-template required counts; fall back to sum of processed tiles
|
||||
const totalRequiredTemplates = this.templatesArray.reduce((sum, t) =>
|
||||
sum + (t.requiredPixelCount || t.pixelCount || 0), 0);
|
||||
const totalRequired = totalRequiredTemplates > 0 ? totalRequiredTemplates : aggRequiredTiles;
|
||||
|
||||
// Turns numbers into formatted number strings. E.g., 1234 -> 1,234 OR 1.234 based on location of user
|
||||
const paintedStr = new Intl.NumberFormat().format(aggPainted);
|
||||
const requiredStr = new Intl.NumberFormat().format(totalRequired);
|
||||
const wrongStr = new Intl.NumberFormat().format(totalRequired - aggPainted); // Used to be aggWrong, but that is bugged
|
||||
|
||||
this.overlay.handleDisplayStatus(
|
||||
`Displaying ${templateCount} template${templateCount == 1 ? '' : 's'}.\nPainted ${paintedStr} / ${requiredStr} • Wrong ${wrongStr}`
|
||||
);
|
||||
} else {
|
||||
this.overlay.handleDisplayStatus(`Displaying ${templateCount} templates.`);
|
||||
}
|
||||
|
||||
return await canvas.convertToBlob({ type: 'image/png' });
|
||||
}
|
||||
|
||||
/** Imports the JSON object, and appends it to any JSON object already loaded
|
||||
|
|
@ -570,8 +345,6 @@ export default class TemplateManager {
|
|||
//const coords = templateValue?.coords?.split(',').map(Number); // "1,2,3,4" -> [1, 2, 3, 4]
|
||||
const tilesbase64 = templateValue.tiles;
|
||||
const templateTiles = {}; // Stores the template bitmap tiles for each tile.
|
||||
let requiredPixelCount = 0; // Global required pixel count for this imported template
|
||||
const paletteMap = new Map(); // Accumulates color counts across tiles (center pixels only)
|
||||
|
||||
for (const tile in tilesbase64) {
|
||||
console.log(tile);
|
||||
|
|
@ -582,36 +355,6 @@ export default class TemplateManager {
|
|||
const templateBlob = new Blob([templateUint8Array], { type: "image/png" }); // Uint8Array -> Blob
|
||||
const templateBitmap = await createImageBitmap(templateBlob) // Blob -> Bitmap
|
||||
templateTiles[tile] = templateBitmap;
|
||||
|
||||
// Count required pixels in this bitmap (center pixels with alpha >= 64 and not #deface)
|
||||
try {
|
||||
const w = templateBitmap.width;
|
||||
const h = templateBitmap.height;
|
||||
const c = new OffscreenCanvas(w, h);
|
||||
const cx = c.getContext('2d', { willReadFrequently: true });
|
||||
cx.imageSmoothingEnabled = false;
|
||||
cx.clearRect(0, 0, w, h);
|
||||
cx.drawImage(templateBitmap, 0, 0);
|
||||
const data = cx.getImageData(0, 0, w, h).data;
|
||||
for (let y = 0; y < h; y++) {
|
||||
for (let x = 0; x < w; x++) {
|
||||
// Only count center pixels of 3x blocks
|
||||
if ((x % this.drawMult) !== 1 || (y % this.drawMult) !== 1) { continue; }
|
||||
const idx = (y * w + x) * 4;
|
||||
const r = data[idx];
|
||||
const g = data[idx + 1];
|
||||
const b = data[idx + 2];
|
||||
const a = data[idx + 3];
|
||||
if (a < 64) { continue; }
|
||||
if (r === 222 && g === 250 && b === 206) { continue; }
|
||||
requiredPixelCount++;
|
||||
const key = activeTemplate.allowedColorsSet.has(`${r},${g},${b}`) ? `${r},${g},${b}` : 'other';
|
||||
paletteMap.set(key, (paletteMap.get(key) || 0) + 1);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Failed to count required pixels for imported tile', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -623,39 +366,12 @@ export default class TemplateManager {
|
|||
//coords: coords
|
||||
});
|
||||
template.chunked = templateTiles;
|
||||
template.requiredPixelCount = requiredPixelCount;
|
||||
// Construct colorPalette from paletteMap
|
||||
const paletteObj = {};
|
||||
for (const [key, count] of paletteMap.entries()) { paletteObj[key] = { count, enabled: true }; }
|
||||
template.colorPalette = paletteObj;
|
||||
// Populate tilePrefixes for fast-scoping
|
||||
try { Object.keys(templateTiles).forEach(k => { template.tilePrefixes?.add(k.split(',').slice(0,2).join(',')); }); } catch (_) {}
|
||||
// Merge persisted palette (enabled/disabled) if present
|
||||
try {
|
||||
const persisted = templates?.[templateKey]?.palette;
|
||||
if (persisted) {
|
||||
for (const [rgb, meta] of Object.entries(persisted)) {
|
||||
if (!template.colorPalette[rgb]) {
|
||||
template.colorPalette[rgb] = { count: meta?.count || 0, enabled: !!meta?.enabled };
|
||||
} else {
|
||||
template.colorPalette[rgb].enabled = !!meta?.enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
// Store storageKey for later writes
|
||||
template.storageKey = templateKey;
|
||||
|
||||
this.templatesArray.push(template);
|
||||
console.log(this.templatesArray);
|
||||
console.log(`^^^ This ^^^`);
|
||||
}
|
||||
}
|
||||
// After importing templates from storage, reveal color UI and request palette list build
|
||||
try {
|
||||
const colorUI = document.querySelector('#bm-contain-colorfilter');
|
||||
if (colorUI) { colorUI.style.display = ''; }
|
||||
window.postMessage({ source: 'blue-marble', bmEvent: 'bm-rebuild-color-list' }, '*');
|
||||
} catch (_) { /* no-op */ }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue