Skip to content

Commit

Permalink
Add background color picker (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
slimbuck authored Oct 28, 2024
1 parent d786742 commit a7f2dc4
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 48 deletions.
84 changes: 43 additions & 41 deletions src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,48 +539,50 @@ const registerEditorEvents = (events: Events, editHistory: EditHistory, scene: S
let compressor: PngCompressor;

events.function('scene.saveScreenshot', async () => {
const texture = scene.camera.entity.camera.renderTarget.colorBuffer;
await texture.downloadAsync();

// construct the png compressor
if (!compressor) {
compressor = new PngCompressor();
}

// @ts-ignore
const pixels = new Uint8ClampedArray(texture.getSource().buffer.slice());

// the render buffer contains premultiplied alpha. so apply background color.
const bkClr = 102;
for (let i = 0; i < pixels.length; i += 4) {
const r = pixels[i];
const g = pixels[i + 1];
const b = pixels[i + 2];
const a = pixels[i + 3];

pixels[i + 0] = r + (255 - a) * bkClr / 255;
pixels[i + 1] = g + (255 - a) * bkClr / 255;
pixels[i + 2] = b + (255 - a) * bkClr / 255;
pixels[i + 3] = 255;
}
events.fire('startSpinner');

try {
const texture = scene.camera.entity.camera.renderTarget.colorBuffer;
await texture.downloadAsync();

// construct the png compressor
if (!compressor) {
compressor = new PngCompressor();
}

const arrayBuffer = await compressor.compress(
new Uint32Array(pixels.buffer),
texture.width,
texture.height
);

// construct filename
const filename = replaceExtension(selectedSplats()?.[0]?.filename ?? 'SuperSplat', '.png');

// download
const blob = new Blob([arrayBuffer], { type: 'octet/stream' });
const url = window.URL.createObjectURL(blob);
const el = document.createElement('a');
el.download = filename;
el.href = url;
el.click();
window.URL.revokeObjectURL(url);
// @ts-ignore
const pixels = new Uint8ClampedArray(texture.getSource().buffer.slice());

// the render buffer contains premultiplied alpha. so apply background color.
const { r, g, b } = events.invoke('bgClr');
for (let i = 0; i < pixels.length; i += 4) {
const a = 255 - pixels[i + 3];
pixels[i + 0] += r * a;
pixels[i + 1] += g * a;
pixels[i + 2] += b * a;
pixels[i + 3] = 255;
}

const arrayBuffer = await compressor.compress(
new Uint32Array(pixels.buffer),
texture.width,
texture.height
);

// construct filename
const filename = replaceExtension(selectedSplats()?.[0]?.filename ?? 'SuperSplat', '.png');

// download
const blob = new Blob([arrayBuffer], { type: 'octet/stream' });
const url = window.URL.createObjectURL(blob);
const el = document.createElement('a');
el.download = filename;
el.href = url;
el.click();
window.URL.revokeObjectURL(url);
} finally {
events.fire('stopSpinner');
}
});
}

Expand Down
29 changes: 25 additions & 4 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,31 @@ const main = async () => {
graphicsDevice
);

// configure body background color
const clr = sceneConfig.bgClr;
const cnv = (v: number) => `${Math.max(0, Math.min(255, (v * 255))).toFixed(0)}`
document.body.style.backgroundColor = `rgba(${cnv(clr.r)},${cnv(clr.g)},${cnv(clr.b)},${clr.a.toFixed(2)})`;
// background color
const clr = { r: -1, g: -1, b: -1 };

const setBgClr = (r: number, g: number, b: number) => {
if (r !== clr.r || g !== clr.g || b !== clr.b) {
clr.r = r;
clr.g = g;
clr.b = b;

const cnv = (v: number) => `${Math.max(0, Math.min(255, (v * 255))).toFixed(0)}`
document.body.style.backgroundColor = `rgba(${cnv(r)},${cnv(g)},${cnv(b)},1)`;

events.fire('bgClr', r, g, b);
}
};

events.on('setBgClr', (r: number, g: number, b: number) => {
setBgClr(r, g, b);
});

events.function('bgClr', () => {
return { r: clr.r, g: clr.g, b: clr.b };
});

setBgClr(sceneConfig.bgClr.r, sceneConfig.bgClr.g, sceneConfig.bgClr.b);

// tool manager
const toolManager = new ToolManager(events);
Expand Down
6 changes: 6 additions & 0 deletions src/ui/localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const localizeInit = () => {

// Options panel
"options": "ANSICHTS OPTIONEN",
"options.bg-clr": "Hintergrundfarbe",
"options.fov": "Blickwinkel (FoV)",
"options.sh-bands": "SH Bänder",
"options.centers-size": "Punktgrößen",
Expand Down Expand Up @@ -201,6 +202,7 @@ const localizeInit = () => {

// Options panel
"options": "VIEW OPTIONS",
"options.bg-clr": "Background Color",
"options.fov": "Field of View",
"options.sh-bands": "SH Bands",
"options.centers-size": "Centers Size",
Expand Down Expand Up @@ -343,6 +345,7 @@ const localizeInit = () => {

// options panel
"options": "OPTIONS D'AFFICHAGE",
"options.bg-clr": "Couleur de fond",
"options.fov": "Champ de vision",
"options.sh-bands": "Ordres d'HS",
"options.centers-size": "Échelle des centres",
Expand Down Expand Up @@ -478,6 +481,7 @@ const localizeInit = () => {

// Options panel
"options": "表示オプション",
"options.bg-clr": "背景色",
"options.fov": "視野 ( FOV )",
"options.sh-bands": "球面調和関数のバンド",
"options.centers-size": "センターサイズ",
Expand Down Expand Up @@ -619,6 +623,7 @@ const localizeInit = () => {

// Options panel
"options": "보기 옵션",
"options.bg-clr": "배경 색상",
"options.fov": "시야각",
"options.sh-bands": "SH 밴드",
"options.centers-size": "센터 크기",
Expand Down Expand Up @@ -760,6 +765,7 @@ const localizeInit = () => {

// Options panel
"options": "视图选项",
"options.bg-clr": "背景颜色",
"options.fov": "视野角",
"options.sh-bands": "SH 带",
"options.centers-size": "中心大小",
Expand Down
9 changes: 7 additions & 2 deletions src/ui/view-panel.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
transform: translate(0, -50%);
right: 102px;
width: 320px;
flex-direction: column;

:not(.pcui-hidden) {
&:not(.pcui-hidden) {
display: flex;
}
flex-direction: column;

& > .view-panel-row {
display: flex;
Expand Down Expand Up @@ -47,6 +47,11 @@
}
}
}

&>.view-panel-row-picker {
margin: 2px 6px;
height: 24px;
}
}

> .view-panel-list-container {
Expand Down
28 changes: 27 additions & 1 deletion src/ui/view-panel.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Vec3 } from 'playcanvas';
import { BooleanInput, Container, Label, SliderInput } from 'pcui';
import { BooleanInput, ColorPicker, Container, Label, SliderInput } from 'pcui';
import { Events } from '../events';
import { Tooltips } from './tooltips';
import { localize } from './localization';
Expand Down Expand Up @@ -39,6 +39,25 @@ class ViewPanel extends Container {
header.append(icon);
header.append(label);

// background color

const bgClrRow = new Container({
class: 'view-panel-row'
});

const bgClrLabel = new Label({
text: localize('options.bg-clr'),
class: 'view-panel-row-label'
});

const bgClrPicker = new ColorPicker({
class: 'view-panel-row-picker',
value: [0.4, 0.4, 0.4]
});

bgClrRow.append(bgClrLabel);
bgClrRow.append(bgClrPicker);

// camera fov

const fovRow = new Container({
Expand Down Expand Up @@ -226,6 +245,7 @@ class ViewPanel extends Container {
poseListContainer.append(poseList);

this.append(header);
this.append(bgClrRow);
this.append(fovRow);
this.append(shBandsRow);
this.append(centersSizeRow);
Expand Down Expand Up @@ -446,6 +466,12 @@ class ViewPanel extends Container {
}
});

// background color

bgClrPicker.on('change', (value: number[]) => {
events.fire('setBgClr', value[0], value[1], value[2]);
});

// camera fov

events.on('camera.fov', (fov: number) => {
Expand Down

0 comments on commit a7f2dc4

Please sign in to comment.