-
Notifications
You must be signed in to change notification settings - Fork 28
/
GeometryUVPreviewPlugin.ts
152 lines (134 loc) · 5.24 KB
/
GeometryUVPreviewPlugin.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import {createDiv, createStyles, getOrCall, onChange, ValOrFunc} from 'ts-browser-helpers'
import styles from './GeometryUVPreviewPlugin.css?inline'
import {CustomContextMenu} from '../../utils'
import {uiFolderContainer, uiToggle} from 'uiconfig.js'
import {IGeometry} from '../../core'
import {UVsDebug} from 'three/examples/jsm/utils/UVsDebug.js'
export interface TargetBlock {
target: ValOrFunc<IGeometry|undefined>
name: string
visible: boolean
div: HTMLDivElement
uvCanvas?: HTMLCanvasElement
}
@uiFolderContainer('Render Target Preview Plugin')
export class GeometryUVPreviewPlugin<TEvent extends string> extends AViewerPluginSync<TEvent> {
static readonly PluginType = 'GeometryUVPreviewPlugin'
@uiToggle('Enabled')
@onChange(GeometryUVPreviewPlugin.prototype.refreshUi) enabled = true
toJSON: any = null
mainDiv: HTMLDivElement = createDiv({id: 'GeometryUVPreviewPluginContainer', addToBody: false})
stylesheet?: HTMLStyleElement
constructor(enabled = true) {
super()
this.enabled = enabled
}
targetBlocks: TargetBlock[] = []
onAdded(viewer: ThreeViewer): void {
super.onAdded(viewer)
viewer.addEventListener('postRender', this._postRender)
this.stylesheet = createStyles(styles, viewer.container)
this.refreshUi()
}
onRemove(viewer: ThreeViewer): void {
viewer.removeEventListener('postRender', this._postRender)
this.stylesheet?.remove()
this.stylesheet = undefined
this.refreshUi()
super.onRemove(viewer)
}
private _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)
}
}
addGeometry(target: ValOrFunc<IGeometry|undefined>, name: string, visible = true): this {
if (!target) return this
const div = document.createElement('div')
const targetDef: TargetBlock = {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: ValOrFunc<IGeometry|undefined>): this {
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: TargetBlock): this {
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(): void {
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() { // for enable/disable functions
this.refreshUi()
}
dispose() {
for (const target of this.targetBlocks) {
this.removeGeometry(target.target)
}
super.dispose()
}
}