xxxxxxxxxx
1287
let aspect = 4 / 3;
let canvasW = 800;
let canvasH = canvasW / aspect;
let canvasHalfW = canvasW / 2;
let canvasHalfH = canvasH / 2;
let topString = canvasH / 4;
let bottomString = canvasH - topString;
let panelW = 260;
let panelH = 260;
let currentImg;
let indexImg;
let currentPalette;
let paletteImg;
let paletteArray;
let hud;
let shaderTarget;
let imageScale;
let selectedIndex = 0;
let flashTimer = 0;
let flashDuration = 1;
let flashInterpolant = 0;
let flashExponent = 2;
let margin = 16;
let sidePanelW = canvasW - panelW * 2 - margin * 3;
let swatchW = 48;
let numberTabW = 48;
let mainSwatchW = sidePanelW - margin * 2.0 - swatchW - numberTabW;
let mainSwatchH = mainSwatchW;
let rgbSwatchW = 32;
let rgbSwatchH = rgbSwatchW;
let rHighlightTimer = 0;
let gHighlightTimer = 0;
let bHighlightTimer = 0;
let rgbHighlightDuration = 1;
let manualTimeStep = false;
let repeatingKeyCode = -1;
let keyInitialDelay = 0.3;
let keyRepeatDelay = 0.02;
let currentKeyDelay = keyInitialDelay;
let keyTimer = 0;
let currentColorName = "";
let currentColorHex = "";
let currentColorExact = false;
let colorSpace;
let clipboard;
let swizzleInput;
let swizzleButton;
let swizzleInputW = 24;
let swizzleButtonW = 70;
let oLX, oRX, oTY, oBY;
let iLX, iRX, iTY, iBY;
let cLX, cRX, cTY, cBY;
let rLX, rRX, rTY, rBY;
// let shaderTargets = [];
// function shaderTarget() { return shaderTargets[shaderTargets.length - 1]; }
function CurrentColor() { return currentPalette.GetColor(selectedIndex); }
function preload()
{
LoadImages();
LoadShaders();
}
function setup()
{
////////////////////////////////////////////////// / / / /
//
// Change this to match any image file name in the Images folder
currentImg = Images.Bilby;
//
// Change this to 1 or greater to use a specific pixel size.
// Leave it at 0 to let the image scale dynamically to fit the panel.
imageScale = 0;
// Regardless, at runtime, press the numpad + and - keys to change this.
//
// Set this to true to allow dynamic scaling to choose non-integer scales.
// Only used when imageScale <= 0.
let allowNonIntegerScaling = false;
//
////////////////////////////////////////////////// / / / /
createCanvas(canvasW, canvasH);
hud = createGraphics(canvasW, canvasH);
noSmooth();
if (imageScale <= 0)
{
let scaleX = (panelW - 4) / currentImg.width;
let scaleY = (panelH - 4) / currentImg.height;
imageScale = min(scaleX, scaleY);
if (!allowNonIntegerScaling)
imageScale = floor(imageScale);
}
let colors = GenerateColorMap(currentImg);
let indices = GenerateSortedIndexMap(colors);
let paletteArray = GeneratePaletteArrayFromIndices(indices);
currentPalette = new Palette(undefined, paletteArray);
indexImg = GenerateIndexImageFromBitmapImage(currentImg, indices);
angleMode(RADIANS);
colorSpace = RGB;
CreateShaderTarget();
UpdateCurrentColorName();
swizzleInput = createInput("RGB");
swizzleInput.size(swizzleInputW);
swizzleInput.input(OnSwizzleInput);
swizzleInput.hide();
swizzleButton = createButton("Swizzle");
swizzleButton.size(swizzleButtonW);
swizzleButton.mouseClicked(OnSwizzlePressed);
swizzleButton.hide();
}
function CreateShaderTarget()
{
// let dw = currentImg.width * imageScale;
// let dh = currentImg.height * imageScale;
// let someTarget = createGraphics(dw, dh, WEBGL);
// Shaders.NearestNeighbor.setUniform("uSource", currentImg);
// Shaders.NearestNeighbor.setUniform("uSourceSize", [currentImg.width, currentImg.height]);
// someTarget.shader(Shaders.NearestNeighbor);
// someTarget.rect(0, 0, 0, 0);
// image(someTarget, 0, 0);
// push();
// fill(255);
// noStroke();
// rect(0, 0, dw, dh);
shaderTarget = createGraphics(currentImg.width, currentImg.height, WEBGL);
}
function draw()
{
hud.clear();
background(100, 100, 200);
let dt = GetDt();
UpdateColorPicker(dt);
DrawBitmap();
DrawIndex();
DrawColorHighlight();
DrawResult();
DrawHud();
if (repeatingKeyCode >= 0)
{
if (keyTimer >= currentKeyDelay)
{
HandleKeypress(repeatingKeyCode, true);
currentKeyDelay = keyRepeatDelay;
keyTimer = 0;
}
keyTimer += dt;
}
}
function keyPressed()
{
repeatingKeyCode = keyCode;
currentKeyDelay = keyInitialDelay;
keyTimer = 0;
return HandleKeypress(keyCode, false);
// return false;
}
function keyReleased()
{
currentKeyDelay = keyInitialDelay;
keyTimer = 0;
if (keyCode === repeatingKeyCode)
repeatingKeyCode = -1;
}
function HandleKeypress(currentKeyCode, repeated)
{
let shift = keyIsDown(SHIFT);
let ctrl = keyIsDown(CONTROL);
let alt = keyIsDown(ALT);
let rgbDelta = shift ? 4 : 1;
if (currentKeyCode === 32) // Spacebar
{
PrintPixels(currentPalette.Image);
}
else if (48 <= currentKeyCode && currentKeyCode <= 57) // numbers
{
let index = currentKeyCode - 48;
if (shift && ctrl)
index += 30;
else if (ctrl)
index += 20;
else if (shift)
index += 10;
SetSelectedIndex(index);
return false;
}
else if (currentKeyCode === 83 && ctrl) // S
{
SavePalette();
SaveIndex();
SaveResult();
return false;
}
else if (currentKeyCode === 67 && ctrl) // C
{
CopyColor();
return false;
}
else if (currentKeyCode === 86 && ctrl) // V
{
PasteColor();
return false;
}
else if (currentKeyCode === 81 && shift) // Q
{
SwapRG();
return false;
}
else if (currentKeyCode === 87 && shift) // W
{
SwapGB();
return false;
}
else if (currentKeyCode === 69 && shift) // E
{
SwapBR();
return false;
}
else if (currentKeyCode === 70) // F
{
flashTimer = 0;
}
// else if (currentKeyCode === 72 && ctrl) // H
// {
// SwitchColorSpace();
//
// return false;
// }
else if (currentKeyCode === UP_ARROW)
{
DecrementSelectedIndex(1, repeated);
}
else if (currentKeyCode === DOWN_ARROW)
{
IncrementSelectedIndex(1, repeated);
}
else if (currentKeyCode === LEFT_ARROW || currentKeyCode === 33) // pgup
{
DecrementSelectedIndex(5, repeated);
}
else if (currentKeyCode === RIGHT_ARROW || currentKeyCode === 34) // pgdn
{
IncrementSelectedIndex(5, repeated);
}
if (!repeated && alt && !ctrl)
{
switch (currentKeyCode)
{
case 65: // A
AdjustR(rgbDelta);
return false;
case 90: // Z
AdjustR(-rgbDelta);
return false;
case 83: // S
AdjustG(rgbDelta);
return false;
case 88: // X
AdjustG(-rgbDelta);
return false;
case 68: // D
AdjustB(rgbDelta);
return false;
case 67: // C
AdjustB(-rgbDelta);
return false;
}
}
else if (currentKeyCode === 107) // num +
{
IncrementImageScale();
}
else if (currentKeyCode === 109) // num -
{
DecrementImageScale();
}
else if (manualTimeStep && currentKeyCode === 190) // .
{
TimeStep();
print(flashTimer / flashPeriod);
}
}
function AdjustR(delta)
{
rHighlightTimer = rgbHighlightDuration;
let currentColor = CurrentColor();
let oldR = currentColor[0];
let newR = oldR;
newR = constrain(oldR + delta, 0, 255);
currentColor[0] = newR;
if (oldR !== newR)
currentPalette.SetColor(selectedIndex, currentColor);
}
function AdjustG(delta)
{
gHighlightTimer = rgbHighlightDuration;
let currentColor = CurrentColor();
let oldG = currentColor[1];
let newG = oldG;
newG = constrain(oldG + delta, 0, 255);
currentColor[1] = newG;
if (oldG !== newG)
currentPalette.SetColor(selectedIndex, currentColor);
}
function AdjustB(delta)
{
bHighlightTimer = rgbHighlightDuration;
let currentColor = CurrentColor();
let oldB = currentColor[2];
let newB = oldB;
newB = constrain(oldB + delta, 0, 255);
currentColor[2] = newB;
if (oldB !== newB)
currentPalette.SetColor(selectedIndex, currentColor);
}
function SavePalette()
{
let name = currentImg.name + ".palette.png";
currentPalette.Image.save(name);
}
function SaveIndex()
{
let name = currentImg.name + ".index.png";
indexImg.save(name);
}
function SaveResult()
{
let name = currentImg.name + ".result.png";
let sw = currentImg.width;
let sh = currentImg.height;
Shaders.TextureSampledPalette.setUniform("uIndexSource", indexImg);
Shaders.TextureSampledPalette.setUniform("uSourceSize", [sw, sh]);
Shaders.TextureSampledPalette.setUniform("uPaletteSource", currentPalette.Image);
Shaders.TextureSampledPalette.setUniform("uPaletteSize", currentPalette.Size);
shaderTarget.shader(Shaders.TextureSampledPalette);
shaderTarget.rect(0, 0, 0, 0);
shaderTarget.save(name);
}
function CopyColor()
{
clipboard = [CurrentColor()];
}
function PasteColor()
{
if (clipboard !== undefined)
currentPalette.SetColor(selectedIndex, clipboard);
}
function SwapRG()
{
rHighlightTimer = rgbHighlightDuration;
gHighlightTimer = rgbHighlightDuration;
let c = CurrentColor();
let temp = c[0];
c[0] = c[1];
c[1] = temp;
currentPalette.SetColor(selectedIndex, c);
}
function SwapGB()
{
gHighlightTimer = rgbHighlightDuration;
bHighlightTimer = rgbHighlightDuration;
let c = CurrentColor();
let temp = c[1];
c[1] = c[2];
c[2] = temp;
currentPalette.SetColor(selectedIndex, c);
}
function SwapBR()
{
bHighlightTimer = rgbHighlightDuration;
rHighlightTimer = rgbHighlightDuration;
let c = CurrentColor();
let temp = c[2];
c[2] = c[0];
c[0] = temp;
currentPalette.SetColor(selectedIndex, c);
}
function OnSwizzleInput()
{
let rgb = swizzleInput.value();
let result = "";
for (const char of rgb)
{
if ("rgbRGBmMlLhHfFxX01".includes(char))
{
if ("lLhHfF".includes(char))
result += char.toUpperCase();
else
result += char;
if (result.length >= 3)
break;
}
}
swizzleInput.value(result);
}
function OnSwizzlePressed()
{
Swizzle(swizzleInput.value());
}
function Swizzle(rgb)
{
if (rgb.length === 0)
return;
if (rgb.length === 1)
rgb += rgb[0];
if (rgb.length === 2)
rgb += rgb[1];
let c = CurrentColor();
let R = c[0];
let G = c[1];
let B = c[2];
let r = round(R / 2);
let g = round(G / 2);
let b = round(B / 2);
let m = min(R, G, B);
let M = max(R, G, B);
let half = round((M + m) / 2);
let luma = round(Luma(R, G, B));
let result = [];
for (let i = 0; i < rgb.length; ++i)
{
let X = c[i];
let x = round(X / 2);
let F = round((X + 255) / 2)
const char = rgb[i];
switch (char)
{
case "r":
result.push(r);
break;
case "g":
result.push(g);
break;
case "b":
result.push(b);
break;
case "R":
result.push(R);
break;
case "G":
result.push(G);
break;
case "B":
result.push(B);
break;
case "m":
result.push(m);
break;
case "M":
result.push(M);
break;
case "L":
result.push(luma);
break;
case "H":
result.push(half);
break;
case "F":
result.push(F);
break;
case "x":
result.push(x);
break;
case "X":
result.push(X);
break;
case "1":
result.push(255);
break;
default: // case "0"
result.push(0);
}
}
if (c[0] != result[0])
rHighlightTimer = rgbHighlightDuration;
if (c[1] != result[1])
gHighlightTimer = rgbHighlightDuration;
if (c[2] != result[2])
bHighlightTimer = rgbHighlightDuration;
currentPalette.SetColor(selectedIndex, result);
}
function SetSelectedIndex(index)
{
selectedIndex = constrain(index, 0, currentPalette.Size - 1);
UpdateCurrentColorName();
flashTimer = 0;
}
function SwitchColorSpace()
{
if (colorSpace === RGB)
SwitchToHsv();
else
SwitchToRgb();
}
function SwitchToRgb()
{
colorSpace = RGB;
}
function SwitchToHsv()
{
// p5 calls it HSB, with B for brightness,
// but I prefer HSV to avoid ambiguity over
// whether B stands for brightness or blue
colorSpace = HSB;
}
function IncrementSelectedIndex(delta, repeated)
{
if (selectedIndex >= currentPalette.Size - 1 && repeated)
return;
if (delta >= 1 && selectedIndex >= currentPalette.Size - 1)
{
SetSelectedIndex(0);
return;
}
let index = min(selectedIndex + delta, currentPalette.Size - 1);
SetSelectedIndex(index);
}
function DecrementSelectedIndex(delta, repeated)
{
if (selectedIndex <= 0 && repeated)
return;
if (delta >= 1 && selectedIndex <= 0)
{
SetSelectedIndex(currentPalette.Size - 1);
return;
}
let index = max(selectedIndex - delta, 0);
SetSelectedIndex(index);
}
function SetImageScale(scale)
{
imageScale = max(1, scale);
// CreateShaderTarget();
}
function IncrementImageScale()
{
SetImageScale(imageScale + 1);
}
function DecrementImageScale()
{
SetImageScale(imageScale - 1);
}
function UpdateCurrentColorName()
{
let colorArray = CurrentColor();
let composite = RgbToInt(colorArray[0], colorArray[1], colorArray[2]);
currentColorHex = "#" + hex(composite, 6);
let ntcMatch = ntc.name(currentColorHex);
currentColorName = ntcMatch[1];
currentColorExact = ntcMatch[2];
}
function UpdateColorPicker(dt)
{
let rgbDelta = keyIsDown(SHIFT) ? 4 : 1;
if (selectedIndex < currentPalette.Size)
{
let currentColor = CurrentColor();
let oldR = currentColor[0];
let oldG = currentColor[1];
let oldB = currentColor[2];
let newR = oldR;
let newG = oldG;
let newB = oldB;
if (!keyIsDown(CONTROL) && !keyIsDown(ALT))// && colorSpace === RGB)
{
if (keyIsDown(65)) // A - red up
AdjustR(rgbDelta);
if (keyIsDown(90)) // Z - red down
AdjustR(-rgbDelta);
if (keyIsDown(83)) // S - green up
AdjustG(rgbDelta);
if (keyIsDown(88)) // X - green down
AdjustG(-rgbDelta);
if (keyIsDown(68)) // D - blue up
AdjustB(rgbDelta);
if (keyIsDown(67)) // C - blue down
AdjustB(-rgbDelta);
}
// else if (!keyIsDown(CONTROL) && !keyIsDown(ALT) && colorSpace !== RGB)
// {
// let hDelta = rgbDelta;
// let sDelta = rgbDelta * 255 / 100;
// let vDelta = sDelta;
// let c = color(oldR, oldG, oldB);
// let h = hue(c);
// let s = saturation(c);
// let v = brightness(c);
// if (keyIsDown(65)) // A - hue up
// h = (h + hDelta) % 360;
// if (keyIsDown(90)) // Z - hue down
// h = (h - hDelta) % 360;
// if (keyIsDown(83)) // S - saturation up
// s = constrain(s + sDelta, 0, 100);
// if (keyIsDown(88)) // X - saturation down
// s = constrain(s - sDelta, 0, 100);
// if (keyIsDown(68)) // D - value up
// v = constrain(v + vDelta, 0, 100);
// if (keyIsDown(67)) // C - value down
// v = constrain(v - vDelta, 0, 100);
// push();
// colorMode(HSB);
// c = color(h, s, v);
// pop();
// newR = red(c);
// newG = green(c);
// newB = blue(c);
// }
// currentColor[0] = newR;
// currentColor[1] = newG;
// currentColor[2] = newB;
// if (oldR !== newR || oldG !== newG || oldB !== newB)
// currentPalette.SetColor(selectedIndex, currentColor);
}
if (currentPalette.Dirty)
{
currentPalette.Clean();
UpdateCurrentColorName();
}
if (!manualTimeStep)
TimeStep(dt);
}
function TimeStep(dt)
{
let f = flashTimer / flashDuration;
if (f >= 1)
flashInterpolant = 0;
else
flashInterpolant = pow(1 - f, flashExponent);
flashTimer += dt;
}
function DrawBitmap()
{
let sw = currentImg.width;
let sh = currentImg.height;
let dw = sw * imageScale;
let dh = sh * imageScale;
Shaders.NearestNeighbor.setUniform("uSource", currentImg);
Shaders.NearestNeighbor.setUniform("uSourceSize", [sw, sh]);
shaderTarget.shader(Shaders.NearestNeighbor);
shaderTarget.rect(0, 0, 0, 0);
strokeWeight(1);
stroke(255);
fill(0, 100);
let panelX = margin;
let panelY = margin;
rect(panelX + 0.5, panelY + 0.5, panelW, panelH);
let imageX = panelX + (panelW / 2 - dw / 2);
let imageY = panelY + (panelH / 2 - dh / 2);
image(shaderTarget, imageX, imageY, dw, dh);
hud.fill(255);
hud.noStroke();
hud.textStyle(BOLD);
hud.textSize(16);
hud.textAlign(CENTER, TOP);
textX = panelX + panelW / 2;
textY = panelY + panelH + 4;
hud.text("Original", textX, textY);
oLX = imageX;
oRX = oLX + dw;
oTY = imageY;
oBY = oTY + dh;
}
function DrawIndex()
{
let sw = currentImg.width;
let sh = currentImg.height;
let dw = sw * imageScale;
let dh = sh * imageScale;
Shaders.NearestNeighbor.setUniform("uSource", indexImg);
Shaders.NearestNeighbor.setUniform("uSourceSize", [sw, sh]);
shaderTarget.shader(Shaders.NearestNeighbor);
shaderTarget.rect(0, 0, 0, 0);
strokeWeight(1);
stroke(255);
fill(0, 100);
let panelX = margin;
let panelY = canvasH - (panelH + margin);
rect(panelX + 0.5, panelY + 0.5, panelW, panelH);
let imageX = panelX + (panelW / 2 - dw / 2);
let imageY = panelY + (panelH / 2 - dh / 2);
image(shaderTarget, imageX, imageY, dw, dh);
hud.fill(255);
hud.noStroke();
hud.textStyle(BOLD);
hud.textSize(16);
hud.textAlign(CENTER, BOTTOM);
textX = panelX + panelW / 2;
textY = panelY;
hud.text("Index", textX, textY);
iLX = imageX;
iRX = iLX + dw;
iTY = imageY;
iBY = iTY + dh;
}
function DrawColorHighlight()
{
let sw = currentImg.width;
let sh = currentImg.height;
let dw = sw * imageScale;
let dh = sh * imageScale;
Shaders.ColorPicker.setUniform("uIndexSource", indexImg);
Shaders.ColorPicker.setUniform("uSourceSize", [sw, sh]);
Shaders.ColorPicker.setUniform("uScaleFactor", imageScale);
Shaders.ColorPicker.setUniform("uPaletteSize", currentPalette.Size);
Shaders.ColorPicker.setUniform("uPaletteSource", currentPalette.Image);
Shaders.ColorPicker.setUniform("uSelectedIndex", selectedIndex);
Shaders.ColorPicker.setUniform("uFlashInterpolant", flashInterpolant);
shaderTarget.shader(Shaders.ColorPicker);
shaderTarget.rect(0, 0, 0, 0);
strokeWeight(1);
stroke(255);
fill(0, 100);
let panelX = panelW + 2.0 * margin;
let panelY = margin;
rect(panelX + 0.5, panelY + 0.5, panelW, panelH);
let imageX = panelX + (panelW / 2 - dw / 2);
let imageY = panelY + (panelH / 2 - dh / 2);
image(shaderTarget, imageX, imageY, dw, dh);
hud.fill(255);
hud.noStroke();
hud.textStyle(BOLD);
hud.textSize(16);
hud.textAlign(CENTER, TOP);
textX = panelX + panelW / 2;
textY = panelY + panelH + 4;
hud.text("Color Highlight", textX, textY);
cLX = imageX;
cRX = cLX + dw;
cTY = imageY;
cBY = cTY + dh;
}
function DrawResult()
{
let sw = currentImg.width;
let sh = currentImg.height;
let dw = sw * imageScale;
let dh = sh * imageScale;
Shaders.TextureSampledPalette.setUniform("uIndexSource", indexImg);
Shaders.TextureSampledPalette.setUniform("uSourceSize", [sw, sh]);
Shaders.TextureSampledPalette.setUniform("uPaletteSource", currentPalette.Image);
Shaders.TextureSampledPalette.setUniform("uPaletteSize", currentPalette.Size);
shaderTarget.shader(Shaders.TextureSampledPalette);
shaderTarget.rect(0, 0, 0, 0);
strokeWeight(1);
stroke(255);
fill(0, 100);
let panelX = panelW + 2.0 * margin;
let panelY = canvasH - (panelH + margin);
rect(panelX + 0.5, panelY + 0.5, panelW, panelH);
let imageX = panelX + (panelW / 2 - dw / 2);
let imageY = panelY + (panelH / 2 - dh / 2);
image(shaderTarget, imageX, imageY, dw, dh);
hud.fill(255);
hud.noStroke();
hud.textStyle(BOLD);
hud.textSize(16);
hud.textAlign(CENTER, BOTTOM);
textX = panelX + panelW / 2;
textY = panelY;
hud.text("Result", textX, textY);
rLX = imageX;
rRX = rLX + dw;
rTY = imageY;
rBY = rTY + dh;
}
function DrawHud()
{
hud.fill(0, 100);
hud.noStroke();
hud.rect(canvasW - sidePanelW, 0, sidePanelW, canvasH);
DrawColorColumn();
DrawInterfacePanel();
image(hud, 0, 0);
}
function DrawColorColumn()
{
let swatchH = floor((canvasH - margin * 2.0) / currentPalette.Size);
let numberTabMaxH = 32;
let numberTabH = min(swatchH - 1, numberTabMaxH);
let numberTabX = canvasW - numberTabW;
let numberTextMaxSize = 16;
let numberTextSize = min(numberTabH * 3 / 4, numberTextMaxSize);
let numberTextX = canvasW - numberTabW / 2;
let swatchX = canvasW - numberTabW - swatchW;
hud.strokeWeight(4);
hud.textAlign(CENTER, CENTER);
hud.textStyle(BOLD);
for (let i = 0; i < currentPalette.Size; ++i)
{
let swatchY = margin + i * swatchH;
let numberTabY = swatchY + (swatchH - numberTabH) / 2;
hud.fill(0, 100);
hud.rect(numberTabX, numberTabY, numberTabW, numberTabH);
let numberTextY = numberTabY + numberTabH / 2 + 1;
if (i === selectedIndex)
{
hud.textSize(numberTextMaxSize);
hud.fill(255, 255, 0);
}
else
{
hud.textSize(numberTextSize);
hud.fill(255, 100);
}
hud.text(i, numberTextX, numberTextY);
let c = currentPalette.GetP5Color(i);
hud.fill(c);
hud.noStroke();
hud.rect(swatchX, swatchY, swatchW, swatchH);
}
let innerBoxX = swatchX - 1.5;
let innerBoxY = margin + selectedIndex * swatchH - 1.5;
let outerBoxX = innerBoxX - 1;
let outerBoxY = innerBoxY - 1;
hud.push();
hud.stroke(255);
hud.strokeWeight(1);
hud.noFill();
hud.rect(innerBoxX, innerBoxY, swatchW + 3, swatchH + 3);
hud.stroke(0);
hud.rect(outerBoxX, outerBoxY, swatchW + 5, swatchH + 5);
hud.pop();
}
function DrawInterfacePanel()
{
let mainSwatchX = canvasW - sidePanelW + margin;
let mainSwatchY = margin;
let c = currentPalette.GetP5Color(selectedIndex);
let ca = CurrentColor();
let r = ca[0];
let g = ca[1];
let b = ca[2];
let h = round(hue(c));
let s = round(saturation(c));
let v = round(brightness(c));
let defaultColor = color(255);
let adjustedColor = color(255, 255, 0);
let rt = (rHighlightTimer / rgbHighlightDuration) ** 3;
let gt = (gHighlightTimer / rgbHighlightDuration) ** 3;
let bt = (bHighlightTimer / rgbHighlightDuration) ** 3;
let rColor = lerpColor(color(255), color(255, 255, 0), rt);
let gColor = lerpColor(color(255), color(255, 255, 0), gt);
let bColor = lerpColor(color(255), color(255, 255, 0), bt);
let dt = GetDt();
rHighlightTimer = max(0, rHighlightTimer - dt);
gHighlightTimer = max(0, gHighlightTimer - dt);
bHighlightTimer = max(0, bHighlightTimer - dt);
hud.push();
hud.stroke(255);
hud.strokeWeight(1);
hud.noFill();
hud.rect(mainSwatchX - 1.5, mainSwatchY - 1.5, mainSwatchW + 3, mainSwatchH + 3);
hud.stroke(0);
hud.rect(mainSwatchX - 2.5, mainSwatchY - 2.5, mainSwatchW + 5, mainSwatchH + 5);
hud.noStroke();
hud.fill(c);
hud.rect(mainSwatchX, mainSwatchY, mainSwatchW, mainSwatchH);
hud.pop();
hud.push();
hud.noStroke();
hud.textAlign(LEFT, TOP);
hud.textSize(10);
hud.fill(255);
hud.textStyle(currentColorExact ? BOLDITALIC : ITALIC);
let colorNameX = mainSwatchX;
let colorNameY = mainSwatchY + mainSwatchH + 5;
hud.text(currentColorName, colorNameX, colorNameY);
hud.text(currentColorHex, colorNameX, colorNameY + hud.textAscent() + hud.textDescent());
hud.pop();
let rgbPanelX = mainSwatchX;
let rgbPanelY = mainSwatchY + mainSwatchH + margin + 16;
let rgbPanelW = mainSwatchW;
let rSwatchY = rgbPanelY;
let gSwatchY = rSwatchY + rgbSwatchH + margin / 2;
let bSwatchY = gSwatchY + rgbSwatchH + margin / 2;
let rgbTabX = rgbPanelX + rgbSwatchW;
let rgbTabMaxW = rgbPanelW - rgbSwatchW;
let rTabW = rgbTabMaxW * r / 255;
let gTabW = rgbTabMaxW * g / 255;
let bTabW = rgbTabMaxW * b / 255;
let rgbTabH = 10;
let rgbTabYOffset = rgbSwatchH - rgbTabH;
let rgbTextX = rgbPanelX + rgbSwatchW / 2;
let rTextY = rSwatchY + rgbSwatchH / 2 + 2;
let gTextY = gSwatchY + rgbSwatchH / 2 + 2;
let bTextY = bSwatchY + rgbSwatchH / 2 + 2;
hud.push();
if (colorSpace === RGB)
{
hud.noStroke();
hud.fill(r, 0, 0);
hud.rect(rgbPanelX, rSwatchY, rgbSwatchW, rgbSwatchH);
hud.rect(rgbTabX, rSwatchY + rgbTabYOffset, rTabW, rgbTabH);
hud.fill(0, g, 0);
hud.rect(rgbPanelX, gSwatchY, rgbSwatchW, rgbSwatchH);
hud.rect(rgbTabX, gSwatchY + rgbTabYOffset, gTabW, rgbTabH);
hud.fill(0, 0, b);
hud.rect(rgbPanelX, bSwatchY, rgbSwatchW, rgbSwatchH);
hud.rect(rgbTabX, bSwatchY + rgbTabYOffset, bTabW, rgbTabH);
hud.fill(255);
hud.stroke(0, 150);
hud.strokeWeight(3);
hud.textStyle(BOLD);
hud.textAlign(CENTER, CENTER);
hud.textSize(16);
hud.text("R", rgbTextX, rTextY);
hud.text("G", rgbTextX, gTextY);
hud.text("B", rgbTextX, bTextY);
hud.textSize(32);
hud.textAlign(RIGHT);
hud.fill(rColor);
hud.text(r, rgbPanelX + rgbPanelW - margin / 2, rTextY);
hud.fill(gColor);
hud.text(g, rgbPanelX + rgbPanelW - margin / 2, gTextY);
hud.fill(bColor);
hud.text(b, rgbPanelX + rgbPanelW - margin / 2, bTextY);
}
else
{
push();
colorMode(HSB);
let hColor = color(h, 100, 100);
let sColor = color(h, s, 100);
let vColor = color(0, 0, v);
let sTabW = rgbTabMaxW * s / 100;
let vTabW = rgbTabMaxW * v / 100;
pop();
let hMarkX = lerp(rgbTabX, rgbTabX + rgbTabMaxW, h / 360) - 1;
let hMarkW = 3;
hud.noStroke();
hud.fill(hColor);
hud.rect(rgbPanelX, rSwatchY, rgbSwatchW, rgbSwatchH);
hud.fill(0, 100);
hud.rect(rgbTabX, rSwatchY + rgbTabYOffset, rgbTabMaxW, rgbTabH);
hud.fill(hColor);
hud.rect(hMarkX, rSwatchY + rgbTabYOffset, hMarkW, rgbTabH);
hud.fill(sColor);
hud.rect(rgbPanelX, gSwatchY, rgbSwatchW, rgbSwatchH);
hud.rect(rgbTabX, gSwatchY + rgbTabYOffset, sTabW, rgbTabH);
hud.fill(vColor);
hud.rect(rgbPanelX, bSwatchY, rgbSwatchW, rgbSwatchH);
hud.rect(rgbTabX, bSwatchY + rgbTabYOffset, vTabW, rgbTabH);
hud.fill(255);
hud.stroke(0, 150);
hud.strokeWeight(3);
hud.textStyle(BOLD);
hud.textAlign(CENTER, CENTER);
hud.textSize(16);
hud.text("H", rgbTextX, rTextY);
hud.text("S", rgbTextX, gTextY);
hud.text("V", rgbTextX, bTextY);
hud.textSize(32);
hud.textAlign(RIGHT);
hud.fill(keyIsDown(65) || keyIsDown(90) ? color(255, 255, 0) : color(255)); // A or Z
hud.text(h, rgbPanelX + rgbPanelW - margin / 2, rTextY);
hud.fill(keyIsDown(83) || keyIsDown(88) ? color(255, 255, 0) : color(255)); // S or X
hud.text(s, rgbPanelX + rgbPanelW - margin / 2, gTextY);
hud.fill(keyIsDown(68) || keyIsDown(67) ? color(255, 255, 0) : color(255)); // D or C
hud.text(v, rgbPanelX + rgbPanelW - margin / 2, bTextY);
}
hud.pop();
let swizzleY = rgbPanelY + 3 * rgbSwatchH + 3 / 2 * margin;
let swizzleButtonX = rgbPanelX + swizzleInputW + 10;
swizzleInput.show();
swizzleInput.position(rgbPanelX, swizzleY);
swizzleButton.show();
swizzleButton.position(swizzleButtonX, swizzleY);
}
function mouseClicked()
{
// swatchW is declared globally
let swatchH = floor((canvasH - margin * 2.0) / currentPalette.Size);
let colLX = canvasW - numberTabW - swatchW;
let colRX = canvasW;
let colTY = margin;
let colBY = colTY + swatchH * currentPalette.Size;
let allowDefault = true;
if (MouseInRect(colLX, colRX, colTY, colBY))
{
let index = floor((mouseY - margin) / swatchH);
SetSelectedIndex(index);
allowDefault = false;
}
else
{
let mo = MouseInRect(oLX, oRX, oTY, oBY);
let mi = MouseInRect(iLX, iRX, iTY, iBY);
let mc = MouseInRect(cLX, cRX, cTY, cBY);
let mr = MouseInRect(rLX, rRX, rTY, rBY);
if (mo || mi || mc || mr)
{
let lx, rx, ty, by;
if (mo)
{
lx = oLX; rx = oRX; ty = oTY; by = oBY;
}
else if (mi)
{
lx = iLX; rx = iRX; ty = iTY; by = iBY;
}
else if (mc)
{
lx = cLX; rx = cRX; ty = cTY; by = cBY;
}
else
{
lx = rLX; rx = rRX; ty = rTY; by = rBY;
}
let px = int(currentImg.width * (mouseX - lx) / (rx - lx));
let py = int(currentImg.height * (mouseY - ty) / (by - ty));
let gray = indexImg.get(px, py);
let r = red(gray);
let index = round((r / 255) * (currentPalette.Size - 1));
SetSelectedIndex(index);
}
allowDefault = false;
}
return allowDefault;
}
function mouseWheel(event)
{
let delta = int(event.delta / 100);
let rgbDelta = -delta * (keyIsDown(SHIFT) ? 4 : 1);
let rgbLX = canvasW - sidePanelW + margin;
let rgbRX = rgbLX + mainSwatchW;
let rgbTY = margin + mainSwatchH + margin + 16;
let rgbBY = rgbTY + rgbSwatchH * 3 + margin;
if (MouseInRect(rgbLX, rgbRX, rgbTY, rgbBY))
{
let rTY = rgbTY;
let rBY = rTY + rgbSwatchH;
let gTY = rBY + margin / 2;
let gBY = gTY + rgbSwatchH;
let bTY = gBY + margin / 2;
let bBY = rgbBY;
if (MouseYWithin(rTY, rBY))
AdjustR(rgbDelta);
else if (MouseYWithin(gTY, gBY))
AdjustG(rgbDelta);
else if (MouseYWithin(bTY, bBY))
AdjustB(rgbDelta);
}
else
{
if (delta > 0)
IncrementSelectedIndex(delta);
else
DecrementSelectedIndex(-delta);
}
return !MouseInCanvas();
}
function MouseXWithin(lX, rX)
{
return lX <= mouseX && mouseX < rX;
}
function MouseYWithin(tY, bY)
{
return tY <= mouseY && mouseY < bY;
}
function MouseInRect(lX, rX, tY, bY)
{
return MouseXWithin(lX, rX) && MouseYWithin(tY, bY);
}
function MouseInCanvas()
{
return MouseInRect(0, width, 0, height);
}
function GetDt() { return deltaTime / 1000; }