threepipe
Version:
A modern 3D viewer framework built on top of three.js, written in TypeScript, designed to make creating high-quality, modular, and extensible 3D experiences on the web simple and enjoyable.
150 lines • 6.03 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { AViewerPluginSync } from '../../viewer';
import { createDiv, createStyles, getOrCall, onChange } from 'ts-browser-helpers';
import styles from './GeometryUVPreviewPlugin.css?inline';
import { CustomContextMenu } from '../../utils';
import { uiFolderContainer, uiToggle } from 'uiconfig.js';
import { UVsDebug } from 'three/examples/jsm/utils/UVsDebug.js';
let GeometryUVPreviewPlugin = class GeometryUVPreviewPlugin extends AViewerPluginSync {
constructor(enabled = true) {
super();
this.enabled = true;
this.toJSON = null;
this.mainDiv = createDiv({ id: 'GeometryUVPreviewPluginContainer', addToBody: false });
this.targetBlocks = [];
this._postRender = () => {
if (!this._viewer)
return;
for (const target of this.targetBlocks) {
if (!target.visible)
continue;
const geo = getOrCall(target.target);
if (!geo?.attributes?.uv) {
// todo draw white or pink
continue;
}
if (!target.uvCanvas) {
target.uvCanvas = UVsDebug(geo, 1024);
target.uvCanvas.style.width = '100%';
target.uvCanvas.style.height = '100%';
}
if (target.uvCanvas && target.uvCanvas.parentElement !== target.div)
target.div.appendChild(target.uvCanvas);
}
};
this.enabled = enabled;
}
onAdded(viewer) {
super.onAdded(viewer);
viewer.addEventListener('postRender', this._postRender);
this.stylesheet = createStyles(styles, viewer.container);
this.refreshUi();
}
onRemove(viewer) {
viewer.removeEventListener('postRender', this._postRender);
this.stylesheet?.remove();
this.stylesheet = undefined;
this.refreshUi();
super.onRemove(viewer);
}
addGeometry(target, name, visible = true) {
if (!target)
return this;
const div = document.createElement('div');
const targetDef = { target, name, div, visible };
div.classList.add('GeometryUVPreviewPluginTarget');
if (!targetDef.visible)
div.classList.add('GeometryUVPreviewPluginCollapsed');
const header = document.createElement('div');
header.classList.add('GeometryUVPreviewPluginTargetHeader');
header.innerText = name;
header.onclick = () => {
targetDef.visible = !targetDef.visible;
if (!targetDef.visible)
div.classList.add('GeometryUVPreviewPluginCollapsed');
else
div.classList.remove('GeometryUVPreviewPluginCollapsed');
this._viewer?.setDirty();
};
header.oncontextmenu = (e) => {
e.preventDefault();
e.stopPropagation();
CustomContextMenu.Create({
'Download': () => this.downloadGeometryUV(targetDef),
'Remove': () => this.removeGeometry(target),
}, e.clientX, e.clientY);
};
div.appendChild(header);
this.mainDiv.appendChild(div);
this.targetBlocks.push(targetDef);
this.refreshUi();
return this;
}
removeGeometry(target) {
const index = this.targetBlocks.findIndex(t => t.target === target);
if (index >= 0) {
const t = this.targetBlocks[index];
this.targetBlocks.splice(index, 1);
t.div.remove();
}
this.refreshUi();
return this;
}
downloadGeometryUV(targetDef) {
if (!this._viewer)
return this;
if (!targetDef.uvCanvas)
return this;
const canvas = targetDef.uvCanvas;
const url = canvas.toDataURL('image/png');
const link = document.createElement('a');
document.body.appendChild(link);
link.style.display = 'none';
link.href = url;
link.download = 'renderTarget.' + 'png';
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
return this;
}
refreshUi() {
if (!this.mainDiv)
return;
if (!this._viewer) {
if (this.mainDiv.parentElement)
this.mainDiv.remove();
this.mainDiv.style.display = 'none';
this.mainDiv.style.zIndex = '1000';
return;
}
if (!this.mainDiv.parentElement)
this._viewer.container?.appendChild(this.mainDiv);
this.mainDiv.style.display = !this.isDisabled() ? 'flex' : 'none';
this.mainDiv.style.zIndex = parseInt(this._viewer.canvas.style.zIndex || '0') + 1 + '';
this._viewer?.setDirty();
}
setDirty() {
this.refreshUi();
}
dispose() {
for (const target of this.targetBlocks) {
this.removeGeometry(target.target);
}
super.dispose();
}
};
GeometryUVPreviewPlugin.PluginType = 'GeometryUVPreviewPlugin';
__decorate([
uiToggle('Enabled'),
onChange(GeometryUVPreviewPlugin.prototype.refreshUi)
], GeometryUVPreviewPlugin.prototype, "enabled", void 0);
GeometryUVPreviewPlugin = __decorate([
uiFolderContainer('Render Target Preview Plugin')
], GeometryUVPreviewPlugin);
export { GeometryUVPreviewPlugin };
//# sourceMappingURL=GeometryUVPreviewPlugin.js.map