Skip to content
This repository was archived by the owner on Dec 12, 2022. It is now read-only.

Commit 407755d

Browse files
committed
Show dependency entities, like materials and geometries on a mesh, in the parameters view, and on selection, selects the dependency
1 parent 857b099 commit 407755d

5 files changed

Lines changed: 145 additions & 77 deletions

File tree

src/app/ContentBridge.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import injection from './injection.js';
2+
import { isUUID } from './utils.js';
23
const $db = Symbol('db');
34
const $sceneGraphs = Symbol('sceneGraphs');
45
const $overviews = Symbol('overviews');
@@ -67,6 +68,29 @@ export default class ContentBridge extends EventTarget {
6768
return /renderer/.test(uuid) ? this[$renderers].get(uuid) : this[$db].get(uuid);
6869
}
6970

71+
getEntityAndDependencies(rootUUID) {
72+
const data = {};
73+
const uuids = [rootUUID];
74+
while (uuids.length) {
75+
const uuid = uuids.shift();
76+
const entity = this.getEntity(uuid);
77+
if (entity && !data[entity.uuid]) {
78+
data[entity.uuid] = entity;
79+
80+
// entities can have several dependencies, like textures on materials,
81+
// or a Mesh's geometry
82+
for (let value of Object.values(entity)) {
83+
if (isUUID(value)) {
84+
uuids.push(value);
85+
}
86+
}
87+
}
88+
}
89+
90+
console.log(`dependencies of ${rootUUID}: ${Object.keys(data)}`);
91+
return data;
92+
}
93+
7094
getResourcesOverview(type) {
7195
return this[$overviews].get(type);
7296
}
@@ -165,6 +189,7 @@ export default class ContentBridge extends EventTarget {
165189
}));
166190
break;
167191
case 'entity':
192+
debugger;
168193
if (data.type === 'renderer') {
169194
this[$renderers].set(data.id, data);
170195
this.dispatchEvent(new CustomEvent('renderer-update', {

src/app/elements/AppElement.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ export default class AppElement extends LitElement {
237237

238238
const showInspector = this.activeEntity && panel !== 'rendering';
239239
const activeEntityData = showInspector ? this.content.getEntity(this.activeEntity) : void 0;
240+
const associatedEntityData = showInspector ? this.content.getEntityAndDependencies(this.activeEntity) : void 0;
240241

241242
const rendererData = panel === 'rendering' && this.activeRenderer ? this.content.getEntity(this.activeRenderer) : void 0;
242243

@@ -401,7 +402,8 @@ export default class AppElement extends LitElement {
401402
<div ?show-inspector=${showInspector} class="inspector-frame frame flex inverse"
402403
visible-when='ready'>
403404
<parameters-view ?enabled=${showInspector}
404-
.entity="${activeEntityData}">
405+
.uuid="${this.activeEntity}"
406+
.entities="${associatedEntityData}">
405407
</parameters-view>
406408
</div>
407409
<title-bar title="${errorText}" class="error ${errorText ? 'show-error' : ''}"></title-bar>

src/app/elements/ParametersViewElement.js

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const commonProps = [{
2020
prop: 'name',
2121
}];
2222

23-
function propsToElements(entity, elements, props) {
23+
function propsToElements(entity, elements, props, entities) {
2424
for (let prop of props) {
2525
if (typeof prop === 'function') {
2626
const result = prop(entity);
@@ -53,14 +53,21 @@ function propsToElements(entity, elements, props) {
5353
key = path.shift();
5454
}
5555

56+
const value = (key in target ) ? target[key] : def;
57+
5658
// For number/int types
5759
let min = 'min' in prop ? prop.min : -Infinity;
5860
let max = 'max' in prop ? prop.max : Infinity;
5961
let step = 'step' in prop ? prop.step : 0.01;
6062
let precision = 'precision' in prop ? prop.precision :
6163
type === 'int' ? 1 : 3;
6264

63-
const value = (key in target ) ? target[key] : def;
65+
// For object types (geometry, material, texture)
66+
let associatedData = {};
67+
if (value && entities && ['geometry', 'material', 'texture'].indexOf(prop.type) !== -1) {
68+
associatedData = entities[value] || {};
69+
}
70+
6471
elements.push(html`
6572
<key-value uuid=${entity.uuid}
6673
key-name="${name}"
@@ -71,6 +78,7 @@ function propsToElements(entity, elements, props) {
7178
.max="${max}"
7279
.step="${step}"
7380
.precision="${precision}"
81+
.data="${associatedData}"
7482
>
7583
</key-value>`);
7684
}
@@ -80,7 +88,12 @@ function propsToElements(entity, elements, props) {
8088
export default class ParametersViewElement extends LitElement {
8189
static get properties() {
8290
return {
83-
entity: { type: Object },
91+
uuid: { type: String },
92+
// Object with uuids as keys to entity data. Most objects will
93+
// only contain the selected entity's data (matching the uuid),
94+
// however things like Mesh will also contain any associated
95+
// material or geometry, etc.
96+
entities: { type: Object },
8497
}
8598
}
8699

@@ -95,20 +108,20 @@ export default class ParametersViewElement extends LitElement {
95108
}
96109

97110
render() {
98-
const entityTitle = this.entity ? getEntityName(this.entity) : '';
111+
const entityData = (this.entities && this.entities[this.uuid]) || null;
112+
const entityTitle = entityData ? getEntityName(entityData) : '';
99113
const elements = [];
100114

101-
if (this.entity) {
102-
const entity = this.entity;
103-
let definition = ObjectTypes[entity.baseType] ||
104-
MaterialTypes[entity.baseType] ||
105-
GeometryTypes[entity.baseType] ||
106-
TextureTypes[entity.baseType];
115+
if (entityData) {
116+
let definition = ObjectTypes[entityData.baseType] ||
117+
MaterialTypes[entityData.baseType] ||
118+
GeometryTypes[entityData.baseType] ||
119+
TextureTypes[entityData.baseType];
107120
if (!definition) {
108121
definition = ObjectTypes.Object3D;
109122
}
110123

111-
propsToElements(entity, elements, [...commonProps, ...definition.props]);
124+
propsToElements(entityData, elements, [...commonProps, ...definition.props], this.entities);
112125
}
113126

114127
return html`

src/app/elements/values/KeyValueElement.js

Lines changed: 88 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { LitElement, html } from '../../../../web_modules/lit-element.js'
2-
import { cssStringToHexNumber, hexNumberToCSSString } from '../../utils.js';
2+
import { getEntityName, cssStringToHexNumber, hexNumberToCSSString } from '../../utils.js';
33

44
const $onChange = Symbol('onChange');
5+
const $onDependencyClick = Symbol('onDependencyClick');
56
const anchor = document.createElement('a');
67
let kvIterator = 0;
78

@@ -20,6 +21,8 @@ export default class KeyValueElement extends LitElement {
2021
max: { type: Number, reflect: true },
2122
step: { type: Number, reflect: true },
2223
precision: { type: Number, reflect: true },
24+
// Optional data for data types (material, geometry)
25+
data: { type: Object },
2326
}
2427
}
2528

@@ -55,70 +58,71 @@ export default class KeyValueElement extends LitElement {
5558

5659
let valueElement;
5760

58-
switch (this.type) {
59-
case 'array':
60-
if (this.value) {
61-
valueElement = html`
62-
<a href="#" @click=${e => this.onDataURLClick(e)}>
63-
array
64-
</a>`;
65-
}
66-
else {
67-
valueElement = html`[]`;
68-
}
69-
break;
70-
case 'enum':
71-
valueElement = html`<enum-value .uuid="${this.uuid}" .type="${this.property}" .value="${this.value}"></enum-value>`;
72-
break;
73-
case 'vec2':
74-
case 'vec3':
75-
case 'vec4':
76-
const arity = this.type === 'vec2' ? 2 :
77-
this.type === 'vec3' ? 3 : 4;
78-
valueElement = [...new Array(arity)].map((_, i) => html`<number-input
79-
.id="${i === 0 ? this._id : ''}"
80-
axis="${i === 0 ? 'x' : i === 1 ? 'y' : i === 2 ? 'z' : 'w'}"
81-
.value="${this.value[i]}"
82-
.min="${this.min}"
83-
.max="${this.max}"
84-
.step="${this.step}"
85-
.precision="${this.precision}"
86-
/>`);
87-
break;
88-
case 'image':
89-
valueElement = html`<image-value .uuid="${this.value}"></image-value>`;
90-
break;
91-
case 'texture':
92-
valueElement = html`<texture-value .uuid="${this.value}"></texture-value>`;
93-
break;
94-
case 'material':
95-
valueElement = html`<material-value .uuid="${this.value}"></material-value>`;
96-
break;
97-
case 'geometry':
98-
valueElement = html`<geometry-value .uuid="${this.value}"></geometry-value>`;
99-
break;
100-
case 'color':
101-
valueElement = html`<input id="${this._id}" type="color" .value="${hexNumberToCSSString(+this.value)}" />`;
102-
break;
103-
case 'boolean':
104-
valueElement = html`<input id="${this._id}" type="checkbox" .checked="${this.value}" />`;
105-
break;
106-
case 'number':
107-
case 'int':
108-
valueElement = html`<number-input
109-
.id="${this._id}"
110-
.value="${this.value}"
111-
.min="${this.min}"
112-
.max="${this.max}"
113-
.step="${this.step}"
114-
.precision="${this.precision}"
115-
/>`;
116-
break;
117-
case 'string':
118-
valueElement = this.value;
119-
break;
120-
default:
121-
valueElement = this.value;
61+
if (this.value == null) {
62+
valueElement = html``;
63+
} else {
64+
switch (this.type) {
65+
case 'array':
66+
if (this.value) {
67+
valueElement = html`
68+
<a href="#" @click=${e => this.onDataURLClick(e)}>
69+
array
70+
</a>`;
71+
}
72+
else {
73+
valueElement = html`[]`;
74+
}
75+
break;
76+
case 'enum':
77+
valueElement = html`<enum-value .uuid="${this.uuid}" .type="${this.property}" .value="${this.value}"></enum-value>`;
78+
break;
79+
case 'vec2':
80+
case 'vec3':
81+
case 'vec4':
82+
const arity = this.type === 'vec2' ? 2 :
83+
this.type === 'vec3' ? 3 : 4;
84+
valueElement = [...new Array(arity)].map((_, i) => html`<number-input
85+
.id="${i === 0 ? this._id : ''}"
86+
axis="${i === 0 ? 'x' : i === 1 ? 'y' : i === 2 ? 'z' : 'w'}"
87+
.value="${this.value[i]}"
88+
.min="${this.min}"
89+
.max="${this.max}"
90+
.step="${this.step}"
91+
.precision="${this.precision}"
92+
/>`);
93+
break;
94+
case 'image':
95+
case 'texture':
96+
case 'material':
97+
case 'geometry':
98+
if (this.data) {
99+
const name = getEntityName(this.data);
100+
valueElement = html`<div class="badge" data-uuid="${this.value}" @click="${this[$onDependencyClick]}">${name}</div>`;
101+
}
102+
break;
103+
case 'color':
104+
valueElement = html`<input id="${this._id}" type="color" .value="${hexNumberToCSSString(+this.value)}" />`;
105+
break;
106+
case 'boolean':
107+
valueElement = html`<input id="${this._id}" type="checkbox" .checked="${this.value}" />`;
108+
break;
109+
case 'number':
110+
case 'int':
111+
valueElement = html`<number-input
112+
.id="${this._id}"
113+
.value="${this.value}"
114+
.min="${this.min}"
115+
.max="${this.max}"
116+
.step="${this.step}"
117+
.precision="${this.precision}"
118+
/>`;
119+
break;
120+
case 'string':
121+
valueElement = this.value;
122+
break;
123+
default:
124+
valueElement = this.value;
125+
}
122126
}
123127

124128
return html`
@@ -153,6 +157,7 @@ export default class KeyValueElement extends LitElement {
153157
padding-left: var(--key-value-padding-left, 10px);
154158
}
155159
160+
#value
156161
#value[type="vec4"] number-input {
157162
width: 25%;
158163
}
@@ -162,6 +167,10 @@ export default class KeyValueElement extends LitElement {
162167
#value[type="vec2"] number-input {
163168
width: 50%;
164169
}
170+
.badge {
171+
background-color: var(--tab-selected-bg-color);
172+
padding: 1px 5px;
173+
}
165174
166175
</style>
167176
<label for="${this._id}">${this.keyName}</label>
@@ -171,6 +180,20 @@ export default class KeyValueElement extends LitElement {
171180
`;
172181
}
173182

183+
[$onDependencyClick](e) {
184+
const target = e.composedPath()[0];
185+
const uuid = target.getAttribute('data-uuid');
186+
if (uuid !== null) {
187+
this.dispatchEvent(new CustomEvent('command', { detail: {
188+
type: 'select-entity',
189+
uuid,
190+
},
191+
bubbles: true,
192+
composed: true,
193+
}));
194+
}
195+
}
196+
174197
[$onChange](e) {
175198

176199
const target = e.composedPath()[0];

src/app/utils.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11

2+
const uuidRegex = /^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}){1}$/
3+
export const isUUID = str => {
4+
return typeof str === 'string' && uuidRegex.test(str);
5+
};
6+
27
export const getEntityName = entity => {
38
return entity.name || entity.baseType;
49
};

0 commit comments

Comments
 (0)