383 lines
10 KiB
JavaScript
383 lines
10 KiB
JavaScript
if (!enabledMods.includes("mods/betterSettings.js")) { enabledMods.unshift("mods/betterSettings.js"); localStorage.setItem("enabledMods", JSON.stringify(enabledMods)); window.location.reload() };
|
|
|
|
var lightmap = [];
|
|
var nextLightmap = [];
|
|
var lightmapWidth, lightmapHeight;
|
|
var lightmapScale = 2;
|
|
var lightSourceBoost = 2;
|
|
var pixelSizeQuarter = pixelSizeHalf / 2;
|
|
|
|
// BetterSettings.js integration
|
|
var lightmap_settingsTab = new SettingsTab("Lightmap");
|
|
|
|
var resolution_setting = new Setting("Resolution (higher number = lower quality)", "resolution", settingType.NUMBER, false, defaultValue=2);
|
|
var falloff_setting = new Setting("Falloff (higher number = higher blur radius)", "falloff", settingType.NUMBER, false, defaultValue=0.8);
|
|
|
|
lightmap_settingsTab.registerSettings("Resolution", resolution_setting);
|
|
lightmap_settingsTab.registerSettings("Falloff", falloff_setting);
|
|
|
|
settingsManager.registerTab(lightmap_settingsTab);
|
|
|
|
|
|
function getRandomElement(arr) {
|
|
return arr[Math.floor(Math.random() * arr.length)];
|
|
}
|
|
|
|
if (!rgbToArray) {
|
|
function rgbToArray(colorString) {
|
|
if (typeof colorString !== "string") {
|
|
console.error("Invalid colorString:", colorString);
|
|
return null;
|
|
}
|
|
if (colorString.startsWith("rgb")) {
|
|
return colorString
|
|
.slice(4, -1)
|
|
.split(",")
|
|
.map(val => parseInt(val.trim()));
|
|
} else if (colorString.startsWith("#")) {
|
|
let hex = colorString.slice(1);
|
|
if (hex.length === 3) {
|
|
hex = hex
|
|
.split("")
|
|
.map(char => char + char)
|
|
.join("");
|
|
}
|
|
if (hex.length !== 6) {
|
|
console.error("Invalid hex color:", colorString);
|
|
return null;
|
|
}
|
|
var r = parseInt(hex.slice(0, 2), 16);
|
|
var g = parseInt(hex.slice(2, 4), 16);
|
|
var b = parseInt(hex.slice(4, 6), 16);
|
|
return [r, g, b];
|
|
}
|
|
console.error("Invalid color format:", colorString);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function scaleList(numbers, scale) {
|
|
return numbers.map(number => number * scale);
|
|
}
|
|
|
|
function initializeLightmap(_width, _height) {
|
|
lightmapWidth = Math.ceil(_width / lightmapScale) + 1;
|
|
lightmapHeight = Math.ceil(_height / lightmapScale) + 1;
|
|
|
|
function createLightmapArray(width_, height_) {
|
|
return Array.from({ length: height_ }, () =>
|
|
Array.from({ length: width_ }, () => ({ color: [0, 0, 0] }))
|
|
);
|
|
}
|
|
|
|
var newLightmap = createLightmapArray(lightmapWidth, lightmapHeight);
|
|
var newNextLightmap = createLightmapArray(lightmapWidth, lightmapHeight);
|
|
|
|
lightmap = newLightmap;
|
|
nextLightmap = newNextLightmap;
|
|
}
|
|
|
|
function deepCopy(source, target) {
|
|
for (var y = 0; y < source.length; y++) {
|
|
target[y] = [];
|
|
for (var x = 0; x < source[y].length; x++) {
|
|
target[y][x] = { ...source[y][x] };
|
|
}
|
|
}
|
|
}
|
|
|
|
function propagateLightmap() {
|
|
if (!lightmap || !lightmap[0]) return;
|
|
|
|
var width = lightmap[0].length;
|
|
var height = lightmap.length;
|
|
var falloff = falloff_setting.value;
|
|
var neighbors = [
|
|
{ dx: 1, dy: 0 },
|
|
{ dx: -1, dy: 0 },
|
|
{ dx: 0, dy: 1 },
|
|
{ dx: 0, dy: -1 }
|
|
];
|
|
|
|
for (var y = 0; y < height; y++) {
|
|
for (var x = 0; x < width; x++) {
|
|
var totalColor = [0, 0, 0];
|
|
var neighborCount = 0;
|
|
|
|
neighbors.forEach(({ dx, dy }) => {
|
|
var nx = x + dx;
|
|
var ny = y + dy;
|
|
if (nx >= 0 && ny >= 0 && nx < width && ny < height) {
|
|
totalColor[0] += lightmap[ny][nx].color[0];
|
|
totalColor[1] += lightmap[ny][nx].color[1];
|
|
totalColor[2] += lightmap[ny][nx].color[2];
|
|
neighborCount++;
|
|
}
|
|
});
|
|
|
|
nextLightmap[y][x] = {
|
|
color: [
|
|
Math.min(Math.max(0, (totalColor[0] / neighborCount) * falloff), 255 * 8),
|
|
Math.min(Math.max(0, (totalColor[1] / neighborCount) * falloff), 255 * 8),
|
|
Math.min(Math.max(0, (totalColor[2] / neighborCount) * falloff), 255 * 8)
|
|
]
|
|
};
|
|
}
|
|
}
|
|
|
|
deepCopy(nextLightmap, lightmap);
|
|
}
|
|
|
|
function rgbToHsv(r, g, b) {
|
|
r /= 255;
|
|
g /= 255;
|
|
b /= 255;
|
|
var max = Math.max(r, g, b);
|
|
var min = Math.min(r, g, b);
|
|
var h, s;
|
|
var v = max;
|
|
var d = max - min;
|
|
s = max === 0 ? 0 : d / max;
|
|
if (max === min) {
|
|
h = 0;
|
|
} else {
|
|
switch (max) {
|
|
case r:
|
|
h = (g - b) / d + (g < b ? 6 : 0);
|
|
break;
|
|
case g:
|
|
h = (b - r) / d + 2;
|
|
break;
|
|
case b:
|
|
h = (r - g) / d + 4;
|
|
break;
|
|
}
|
|
h /= 6;
|
|
}
|
|
return [h, s, v];
|
|
}
|
|
|
|
function hsvToRgb(h, s, v) {
|
|
var i = Math.floor(h * 6);
|
|
var f = h * 6 - i;
|
|
var p = v * (1 - s);
|
|
var q = v * (1 - f * s);
|
|
var t = v * (1 - (1 - f) * s);
|
|
var r, g, b;
|
|
|
|
switch (i % 6) {
|
|
case 0:
|
|
r = v;
|
|
g = t;
|
|
b = p;
|
|
break;
|
|
case 1:
|
|
r = q;
|
|
g = v;
|
|
b = p;
|
|
break;
|
|
case 2:
|
|
r = p;
|
|
g = v;
|
|
b = t;
|
|
break;
|
|
case 3:
|
|
r = p;
|
|
g = q;
|
|
b = v;
|
|
break;
|
|
case 4:
|
|
r = t;
|
|
g = p;
|
|
b = v;
|
|
break;
|
|
case 5:
|
|
r = v;
|
|
g = p;
|
|
b = q;
|
|
break;
|
|
}
|
|
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
|
|
}
|
|
|
|
function renderLightmapPrePixel(ctx) {
|
|
if (!lightmap || !lightmap[0]) return;
|
|
var _width = lightmap[0].length;
|
|
var _height = lightmap.length;
|
|
|
|
for (var y = 0; y < _height; y++) {
|
|
for (var x = 0; x < _width; x++) {
|
|
var color = lightmap[y][x].color;
|
|
var r = color[0];
|
|
var g = color[1];
|
|
var b = color[2];
|
|
|
|
if (r > 16 || g > 16 || b > 16) {
|
|
var hsv = rgbToHsv(r, g, b);
|
|
var newColor = hsvToRgb(hsv[0], hsv[1], 1);
|
|
var alpha = hsv[2];
|
|
|
|
ctx.globalAlpha = 1.0;
|
|
ctx.fillStyle = `rgba(${newColor[0]}, ${newColor[1]}, ${newColor[2]}, ${alpha * 0.4})`;
|
|
ctx.fillRect(
|
|
x * pixelSize * lightmapScale,
|
|
y * pixelSize * lightmapScale,
|
|
pixelSize * lightmapScale,
|
|
pixelSize * lightmapScale
|
|
);
|
|
|
|
ctx.fillStyle = `rgba(${newColor[0]}, ${newColor[1]}, ${newColor[2]}, ${alpha * 0.25})`;
|
|
ctx.fillRect(
|
|
(x * pixelSize - pixelSizeHalf) * lightmapScale,
|
|
(y * pixelSize - pixelSizeHalf) * lightmapScale,
|
|
pixelSize * lightmapScale * 2,
|
|
pixelSize * lightmapScale * 2
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Main loop
|
|
renderPrePixel(function(ctx) {
|
|
// Reset lightmap if resolution changed
|
|
if (resolution_setting.value != lightmapScale) {
|
|
lightmapScale = resolution_setting.value;
|
|
initializeLightmap(width, height);
|
|
return;
|
|
}
|
|
|
|
if (!paused) {
|
|
propagateLightmap();
|
|
}
|
|
renderLightmapPrePixel(ctx);
|
|
});
|
|
|
|
function glowItsOwnColor(pixel) {
|
|
if (!pixel.color) return;
|
|
var x = Math.floor(pixel.x / lightmapScale);
|
|
var y = Math.floor(pixel.y / lightmapScale);
|
|
try {
|
|
lightmap[y][x] = { color: scaleList(rgbToArray(pixel.color), lightSourceBoost) };
|
|
} catch (e) {
|
|
console.log(e, pixel, pixel.color, rgbToArray(pixel.color), x, y)
|
|
}
|
|
}
|
|
|
|
function glowItsOwnColorIfPowered(pixel) {
|
|
if (!pixel.charge || pixel.charge <= 0) return;
|
|
if (!pixel.color) return;
|
|
var x = Math.floor(pixel.x / lightmapScale);
|
|
var y = Math.floor(pixel.y / lightmapScale);
|
|
lightmap[y][x] = { color: scaleList(rgbToArray(pixel.color), lightSourceBoost) };
|
|
}
|
|
|
|
function glowColor(pixel, color) {
|
|
if (!color) return;
|
|
var x = Math.floor(pixel.x / lightmapScale);
|
|
var y = Math.floor(pixel.y / lightmapScale);
|
|
lightmap[y][x] = { color: scaleList(color, lightSourceBoost) };
|
|
}
|
|
|
|
function glowRadiationColor(pixel) {
|
|
var x = Math.floor(pixel.x / lightmapScale);
|
|
var y = Math.floor(pixel.y / lightmapScale);
|
|
lightmap[y][x] = { color: scaleList(radColor, lightSourceBoost) };
|
|
}
|
|
|
|
var originalStrangeMatterTick = elements.strange_matter.tick;
|
|
elements.strange_matter.tick = function(pixel) {
|
|
originalStrangeMatterTick(pixel);
|
|
glowColor(pixel, strangeMatterColor);
|
|
};
|
|
|
|
var originalLightTick = elements.light.tick;
|
|
elements.light.tick = function(pixel) {
|
|
originalLightTick(pixel);
|
|
glowItsOwnColor(pixel);
|
|
};
|
|
|
|
var originalLiquidLightTick = elements.liquid_light.tick;
|
|
elements.liquid_light.tick = function(pixel) {
|
|
originalLiquidLightTick(pixel);
|
|
glowItsOwnColor(pixel);
|
|
};
|
|
|
|
var originalLaserTick = elements.laser.tick;
|
|
elements.laser.tick = function(pixel) {
|
|
originalLaserTick(pixel);
|
|
glowColor(pixel, scaleList(rgbToArray(pixel.color), 0.5));
|
|
};
|
|
|
|
var originalFireTick3 = elements.fire.tick;
|
|
elements.fire.tick = function(pixel) {
|
|
originalFireTick3(pixel);
|
|
glowItsOwnColor(pixel);
|
|
};
|
|
|
|
var originalColdFireTick2 = elements.cold_fire.tick;
|
|
elements.cold_fire.tick = function(pixel) {
|
|
originalColdFireTick2(pixel);
|
|
glowItsOwnColor(pixel);
|
|
};
|
|
|
|
var originalFlashTick = elements.flash.tick;
|
|
elements.flash.tick = function(pixel) {
|
|
originalFlashTick(pixel);
|
|
glowItsOwnColor(pixel);
|
|
};
|
|
|
|
var originalRainbowTick = elements.rainbow.tick;
|
|
elements.rainbow.tick = function(pixel) {
|
|
originalRainbowTick(pixel);
|
|
glowItsOwnColor(pixel);
|
|
};
|
|
|
|
var originalFireflyTick = elements.firefly.tick;
|
|
elements.firefly.tick = function(pixel) {
|
|
originalFireflyTick(pixel);
|
|
var x = Math.floor(pixel.x / lightmapScale);
|
|
var y = Math.floor(pixel.y / lightmapScale);
|
|
var tickMod = pixelTicks % pixel.fff;
|
|
var num;
|
|
|
|
if (tickMod <= 2) num = 1;
|
|
else if (tickMod <= 3) num = 0.75;
|
|
else if (tickMod <= 4) num = 0.5;
|
|
else if (tickMod <= 5) num = 0.25;
|
|
else return;
|
|
|
|
lightmap[y][x] = { color: scaleList(fireflyColor, num) };
|
|
};
|
|
|
|
elements.electric.tick = pixel => glowColor(pixel, scaleList(getRandomElement(sparkColors), 0.5));
|
|
|
|
elements.neon.tick = glowItsOwnColorIfPowered;
|
|
elements.led.tick = glowItsOwnColorIfPowered;
|
|
// elements.led_r.tick = glowItsOwnColorIfPowered;
|
|
// elements.led_g.tick = glowItsOwnColorIfPowered;
|
|
// elements.led_b.tick = glowItsOwnColorIfPowered;
|
|
elements.light_bulb.behaviorOn = null;
|
|
elements.light_bulb.tick = glowItsOwnColorIfPowered;
|
|
elements.sun.tick = glowItsOwnColor;
|
|
elements.magma.tick = glowItsOwnColor;
|
|
elements.plasma.tick = glowItsOwnColor;
|
|
elements.fw_ember.tick = glowItsOwnColor;
|
|
|
|
var radioactiveElements = [
|
|
"uranium", "radiation", "rad_glass", "fallout",
|
|
"molten_uranium", "rad_shard", "rad_cloud", "rad_steam"
|
|
];
|
|
radioactiveElements.forEach(element => {
|
|
elements[element].tick = glowRadiationColor;
|
|
});
|
|
|
|
var fireflyColor = [240, 255, 70];
|
|
var radColor = [75, 100, 30];
|
|
var strangeMatterColor = [220 * 0.3, 255 * 0.3, 210 * 0.3];
|
|
var sparkColors = [[255, 210, 120], [255, 140, 10]];
|
|
|
|
runAfterReset(() => {
|
|
initializeLightmap(width, height);
|
|
});
|