286 lines
17 KiB
JavaScript
286 lines
17 KiB
JavaScript
import { app } from "../../../scripts/app.js";
|
|
|
|
app.registerExtension({
|
|
name: "AdvancedRelightNode.UI.FinalComplete",
|
|
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
if (nodeData.name === "RelightNode") {
|
|
|
|
const onExecuted = nodeType.prototype.onExecuted;
|
|
nodeType.prototype.onExecuted = function(message) {
|
|
onExecuted?.apply(this, arguments);
|
|
|
|
if (message?.previews) {
|
|
const imageUrl = message.previews[0];
|
|
|
|
const img = new Image();
|
|
img.src = imageUrl + `?t=${new Date().getTime()}`;
|
|
|
|
img.onload = () => {
|
|
const anchorWidget = this.widgets.find(w => w.name === "ui_anchor");
|
|
|
|
this.previewImage = img;
|
|
|
|
this.applyAnchorResize();
|
|
const newSize = this.computeSize();
|
|
this.size[1] = newSize[1];
|
|
this.setDirtyCanvas(true, true);
|
|
delete anchorWidget.computeSize;
|
|
this.drawSlider();
|
|
};
|
|
|
|
img.onerror = () => {
|
|
console.error(`[Relight Node] ERREUR: Impossible de charger l'image depuis l'URL directe: ${imageUrl}`);
|
|
};
|
|
}
|
|
};
|
|
|
|
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function () {
|
|
onNodeCreated?.apply(this, arguments);
|
|
|
|
const node = this;
|
|
|
|
this.lights = [{}, {}];
|
|
this.draggedLightIndex = null;
|
|
node._customFlags ??= {};
|
|
if (node._customFlags.hasImageResizeRatio === undefined)
|
|
node._customFlags.hasImageResizeRatio = false;
|
|
node._onetimeFlags ??= {};
|
|
if (node._onetimeFlags.haspassed === undefined)
|
|
node._onetimeFlags.haspassed = false;
|
|
node._onetimeFlags.counter = 0;
|
|
this.previewImage = null;
|
|
this.imageRect = { x: 0, y: 0, w: 0, h: 0 };
|
|
|
|
requestAnimationFrame(() => {
|
|
if (this.sliderInitialized) return;
|
|
this.sliderInitialized = true;
|
|
this.lights[0].xWidget = this.widgets.find((w) => w.name === "light_x_1");
|
|
this.lights[0].yWidget = this.widgets.find((w) => w.name === "light_y_1");
|
|
this.lights[0].typeWidget = this.widgets.find(w => w.name === "light_type_1");
|
|
this.lights[0].pointSizeWidget = this.widgets.find(w => w.name === "point_size_1");
|
|
this.lights[0].intensityWidget = this.widgets.find(w => w.name === "intensity_1");
|
|
this.lights[0].neonWidgets = this.widgets.filter(w => ["neon_length_1", "neon_angle_1"].includes(w.name));
|
|
const enableLight2Widget = this.widgets.find(w => w.name === "enable_light_2");
|
|
this.lights[1].xWidget = this.widgets.find((w) => w.name === "light_x_2");
|
|
this.lights[1].yWidget = this.widgets.find((w) => w.name === "light_y_2");
|
|
this.lights[1].zWidget = this.widgets.find(w => w.name === "light_z_2");
|
|
this.lights[1].typeWidget = this.widgets.find(w => w.name === "light_type_2");
|
|
this.lights[1].pointSizeWidget = this.widgets.find(w => w.name === "point_size_2");
|
|
this.lights[1].intensityWidget = this.widgets.find(w => w.name === "intensity_2");
|
|
this.lights[1].neonWidgets = this.widgets.filter(w => ["neon_length_2", "neon_angle_2"].includes(w.name));
|
|
const anchorWidget = this.widgets.find((w) => w.name === "ui_anchor");
|
|
const maskEnabledWidget = this.widgets.find(w => w.name === "mask_enabled");
|
|
const maskWidgets = this.widgets.filter(w => ["brush_intensity", "brush_softness", "mask_intensity_mult", "mask_gamma_mult"].includes(w.name));
|
|
const spacer1 = this.widgets.find((w) => w.name === "spacer_1");
|
|
const spacer2 = this.widgets.find((w) => w.name === "spacer_2");
|
|
const lightX1 = this.widgets.find(w => w.name === "light_x_1");
|
|
const lightY1 = this.widgets.find(w => w.name === "light_y_1");
|
|
const lightX2 = this.widgets.find(w => w.name === "light_x_2");
|
|
const lightY2 = this.widgets.find(w => w.name === "light_y_2");
|
|
|
|
if (!anchorWidget || !anchorWidget.inputEl) { return; }
|
|
|
|
lightX1.hidden = true;
|
|
lightX1.computeSize = () => [0, -4]; // Supprime l'espace vertical
|
|
lightY1.hidden = true;
|
|
lightY1.computeSize = () => [0, -4]; // Supprime l'espace vertical
|
|
lightX2.hidden = true;
|
|
lightX2.computeSize = () => [0, -4]; // Supprime l'espace vertical
|
|
lightY2.hidden = true;
|
|
lightY2.computeSize = () => [0, -4]; // Supprime l'espace vertical
|
|
spacer1.hidden = true;
|
|
spacer2.hidden = true;
|
|
|
|
anchorWidget.computeSize = (width) => [width, 256];
|
|
|
|
const sliderCanvas = document.createElement("canvas");
|
|
sliderCanvas.style.width = "100%";
|
|
sliderCanvas.style.height = "100%";
|
|
sliderCanvas.style.cursor = "pointer";
|
|
const container = anchorWidget.inputEl.parentElement;
|
|
container.replaceChild(sliderCanvas, anchorWidget.inputEl);
|
|
container.style.padding = "0";
|
|
const ctx = sliderCanvas.getContext("2d");
|
|
|
|
const drawSlider = () => {
|
|
const rect = sliderCanvas.getBoundingClientRect();
|
|
if (sliderCanvas.width !== rect.width || sliderCanvas.height !== rect.height) {
|
|
sliderCanvas.width = rect.width;
|
|
sliderCanvas.height = rect.height;
|
|
}
|
|
const width = sliderCanvas.width;
|
|
const height = sliderCanvas.height;
|
|
ctx.fillStyle = "rgba(0,0,0,1)";
|
|
ctx.fillRect(0, 0, width, height);
|
|
if (node.previewImage && node.previewImage.complete) {
|
|
const imgRatio = node.previewImage.naturalWidth / node.previewImage.naturalHeight;
|
|
const canvasRatio = width / height;
|
|
let destWidth, destHeight, destX, destY;
|
|
if (imgRatio > canvasRatio) {
|
|
destWidth = width; destHeight = width / imgRatio;
|
|
destX = 0; destY = (height - destHeight) / 2;
|
|
} else {
|
|
destHeight = height; destWidth = height * imgRatio;
|
|
destY = 0; destX = (width - destWidth) / 2;
|
|
}
|
|
ctx.drawImage(node.previewImage, destX, destY, destWidth, destHeight);
|
|
node.imageRect = { x: destX, y: destY, w: destWidth, h: destHeight };
|
|
} else {
|
|
node.imageRect = { x: 0, y: 0, w: width, h: height };
|
|
}
|
|
node.lights.forEach((light, index) => {
|
|
if (index > 0 && !enableLight2Widget.value) return;
|
|
const lightCenterX = node.imageRect.x + (light.xWidget.value * node.imageRect.w);
|
|
const lightCenterY = node.imageRect.y + (light.yWidget.value * node.imageRect.h);
|
|
ctx.save();
|
|
ctx.globalCompositeOperation = 'overlay';
|
|
if (light.typeWidget.value === "Point") {
|
|
let radius;
|
|
|
|
if (index === 0) {
|
|
radius = (light.pointSizeWidget.value * 100) + (light.intensityWidget.value * 3);
|
|
} else {
|
|
radius = (light.pointSizeWidget.value * 500) + (light.intensityWidget.value * 3);
|
|
}
|
|
|
|
const gradient = ctx.createRadialGradient(lightCenterX, lightCenterY, 0, lightCenterX, lightCenterY, radius);
|
|
gradient.addColorStop(0, "rgba(255, 255, 240, 0.9)");
|
|
gradient.addColorStop(1, "rgba(255, 255, 240, 0)");
|
|
ctx.fillStyle = gradient;
|
|
ctx.beginPath();
|
|
ctx.arc(lightCenterX, lightCenterY, radius, 0, 2 * Math.PI);
|
|
ctx.fill();
|
|
}
|
|
ctx.restore();
|
|
Object.assign(ctx, { fillStyle: "rgba(255,255,255,0.8)", strokeStyle: "black", lineWidth: 2 });
|
|
ctx.beginPath();
|
|
ctx.arc(lightCenterX, lightCenterY, 7, 0, 2 * Math.PI);
|
|
ctx.fill();
|
|
ctx.stroke();
|
|
});
|
|
};
|
|
this.drawSlider = drawSlider;
|
|
|
|
const applyAnchorResize = () => {
|
|
node.canvasHeight = sliderCanvas.getBoundingClientRect().height;
|
|
const nodeContentWidth = node.size[0] - 20;
|
|
if (node.previewImage) {
|
|
node.aspectRatio = node.previewImage.naturalHeight / node.previewImage.naturalWidth;
|
|
const newHeight = nodeContentWidth * node.aspectRatio
|
|
anchorWidget.computeSize = (w) => [w, newHeight];
|
|
} else {
|
|
//if (!node._onetimeFlags.haspassed && (node._onetimeFlags.counter === 1 || node._onetimeFlags.counter === 2)) {
|
|
node._onetimeFlags.goodratio = 256 / node.canvasHeight;
|
|
node._onetimeFlags.haspassed = true;
|
|
//}
|
|
node._onetimeFlags.counter++;
|
|
const ratio = node._onetimeFlags.goodratio;
|
|
anchorWidget.computeSize = (width) => [width, node.canvasHeight * ratio];
|
|
}
|
|
};
|
|
this.applyAnchorResize = applyAnchorResize;
|
|
|
|
const onDragMove = (event) => {
|
|
if (!isDragging || node.draggedLightIndex === null) return;
|
|
const rect = sliderCanvas.getBoundingClientRect();
|
|
const mouseX = event.clientX - rect.left;
|
|
const mouseY = event.clientY - rect.top;
|
|
let valueX = (mouseX - node.imageRect.x) / node.imageRect.w;
|
|
let valueY = (mouseY - node.imageRect.y) / node.imageRect.h;
|
|
const activeLight = node.lights[node.draggedLightIndex];
|
|
activeLight.xWidget.value = Math.max(0, Math.min(1, valueX));
|
|
activeLight.yWidget.value = Math.max(0, Math.min(1, valueY));
|
|
drawSlider();
|
|
};
|
|
let isDragging = false;
|
|
const onDragEnd = () => {
|
|
if (!isDragging) return;
|
|
isDragging = false;
|
|
if (node.draggedLightIndex !== null) {
|
|
const activeLight = node.lights[node.draggedLightIndex];
|
|
activeLight.xWidget.setValue(activeLight.xWidget.value);
|
|
activeLight.yWidget.setValue(activeLight.yWidget.value);
|
|
node.draggedLightIndex = null;
|
|
}
|
|
window.removeEventListener("mousemove", onDragMove);
|
|
window.removeEventListener("mouseup", onDragEnd);
|
|
node.setDirtyCanvas(true);
|
|
};
|
|
sliderCanvas.addEventListener("mousedown", (event) => {
|
|
const rect = sliderCanvas.getBoundingClientRect();
|
|
const mouseX = event.clientX - rect.left;
|
|
const mouseY = event.clientY - rect.top;
|
|
let closestIndex = 0;
|
|
let minDistance = Infinity;
|
|
node.lights.forEach((light, index) => {
|
|
if (index > 0 && !enableLight2Widget.value) return;
|
|
const lightX = node.imageRect.x + light.xWidget.value * node.imageRect.w;
|
|
const lightY = node.imageRect.y + light.yWidget.value * node.imageRect.h;
|
|
const distance = Math.sqrt(Math.pow(mouseX - lightX, 2) + Math.pow(mouseY - lightY, 2));
|
|
if (distance < minDistance) {
|
|
minDistance = distance;
|
|
closestIndex = index;
|
|
}
|
|
});
|
|
node.draggedLightIndex = closestIndex;
|
|
isDragging = true;
|
|
window.addEventListener("mousemove", onDragMove);
|
|
window.addEventListener("mouseup", onDragEnd);
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
onDragMove(event);
|
|
});
|
|
new ResizeObserver(drawSlider).observe(container);
|
|
const setWidgetVisibility = (widget, isHidden) => {
|
|
if (!widget) return;
|
|
widget.hidden = isHidden;
|
|
if (isHidden) {
|
|
widget.computeSize = () => [0, -4];
|
|
} else {
|
|
delete widget.computeSize;
|
|
}
|
|
};
|
|
const toggleLightWidgets = (light, shouldHide) => {
|
|
if (!light.typeWidget) return;
|
|
const isNeon = light.typeWidget.value === "Neon";
|
|
light.neonWidgets.forEach(w => setWidgetVisibility(w, shouldHide || !isNeon));
|
|
setWidgetVisibility(light.pointSizeWidget, shouldHide || isNeon);
|
|
//setWidgetVisibility(light.xWidget, shouldHide);
|
|
//setWidgetVisibility(light.yWidget, shouldHide);
|
|
setWidgetVisibility(light.zWidget, shouldHide);
|
|
setWidgetVisibility(light.typeWidget, shouldHide);
|
|
setWidgetVisibility(light.intensityWidget, shouldHide);
|
|
};
|
|
const toggleMaskWidgets = () => {
|
|
const isEnabled = maskEnabledWidget.value;
|
|
maskWidgets.forEach(w => setWidgetVisibility(w, !isEnabled));
|
|
applyAnchorResize();
|
|
const newSize = node.computeSize();
|
|
node.size[1] = newSize[1];
|
|
node.setDirtyCanvas(true, true);
|
|
delete anchorWidget.computeSize;
|
|
};
|
|
const updateAllWidgetsVisibility = () => {
|
|
toggleLightWidgets(node.lights[0], false);
|
|
toggleLightWidgets(node.lights[1], !enableLight2Widget.value);
|
|
applyAnchorResize();
|
|
const newSize = node.computeSize();
|
|
node.size[1] = newSize[1];
|
|
node.setDirtyCanvas(true, true);
|
|
delete anchorWidget.computeSize;
|
|
};
|
|
enableLight2Widget.callback = () => { updateAllWidgetsVisibility(); drawSlider(); };
|
|
if(maskEnabledWidget) maskEnabledWidget.callback = toggleMaskWidgets;
|
|
this.lights[0].typeWidget.callback = updateAllWidgetsVisibility;
|
|
this.lights[1].typeWidget.callback = updateAllWidgetsVisibility;
|
|
setTimeout(() => {
|
|
updateAllWidgetsVisibility();
|
|
toggleMaskWidgets();
|
|
drawSlider();
|
|
}, 50);
|
|
});
|
|
};
|
|
}
|
|
},
|
|
}); |