@woosh/meep-engine 2.34.1 → 2.34.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -88,9 +88,15 @@ test('replaceAnotherVertex', () => {
88
88
  v_b.addEdge(e_b);
89
89
 
90
90
  f_a.setVertexAt(0, v_a);
91
+ f_a.setVertexAt(1, new TopoVertex());
92
+ f_a.setVertexAt(2, new TopoVertex());
93
+
91
94
  e_a.v0 = v_a;
92
95
 
93
96
  f_b.setVertexAt(0, v_b);
97
+ f_b.setVertexAt(1, new TopoVertex());
98
+ f_b.setVertexAt(2, new TopoVertex());
99
+
94
100
  e_b.v0 = v_b;
95
101
 
96
102
  // verify assumptions about topology
@@ -1,4 +1,4 @@
1
- import { objectDeepEquals } from "./objectDeepEquals.d.ts";
1
+ import { objectDeepEquals } from "./objectDeepEquals.js";
2
2
 
3
3
  test('objectDeepEquals', () => {
4
4
  expect(objectDeepEquals({}, {})).toBe(true);
package/editor/Editor.js CHANGED
@@ -25,7 +25,7 @@ import TopDownCameraController from "../engine/graphics/ecs/camera/topdown/TopDo
25
25
  import { Transform } from "../engine/ecs/transform/Transform.js";
26
26
  import TopDownCameraControllerSystem, { setCameraControllerFromTransform } from "../engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js";
27
27
  import { downloadAsFile } from "../core/binary/ByteArrayTools.js";
28
- import BinaryBufferSerialization from "../engine/ecs/storage/BinaryBufferSerializer.js";
28
+ import BinaryBufferSerializer from "../engine/ecs/storage/BinaryBufferSerializer.js";
29
29
  import { EncodingBinaryBuffer } from "../core/binary/EncodingBinaryBuffer.js";
30
30
  import { EntityComponentDataset } from "../engine/ecs/EntityComponentDataset.js";
31
31
  import InputControllerSystem from "../engine/input/ecs/systems/InputControllerSystem.js";
@@ -383,7 +383,7 @@ function Editor() {
383
383
  // Set music tracks back to time=0
384
384
  resetSoundEmitterTracks(dataset);
385
385
 
386
- const serializer = new BinaryBufferSerialization();
386
+ const serializer = new BinaryBufferSerializer();
387
387
  serializer.registry = engine.binarySerializationRegistry;
388
388
 
389
389
  const state = new EncodingBinaryBuffer();
@@ -328,7 +328,6 @@ export class EngineHarness {
328
328
  * @param {number} [cameraEntity]
329
329
  * @param {Engine} engine
330
330
  * @param {number} [sensitivity]
331
- * @param {Element} domElement
332
331
  * @param {EntityComponentDataset} [ecd]
333
332
  * @returns {EntityBuilder}
334
333
  */
@@ -23,7 +23,7 @@ async function decode_png(png_bytes) {
23
23
  width,
24
24
  height,
25
25
  itemSize: uint_channels.itemSize,
26
- bitDepth: uint_channels.bitDepth
26
+ bitDepth: png.bitDepth
27
27
  });
28
28
  });
29
29
  }
@@ -41,6 +41,12 @@ export class ImageRGBADataLoader extends AssetLoader {
41
41
  return await this.decoder.decode(new Uint8Array(array_buffer));
42
42
  }
43
43
 
44
+ /**
45
+ *
46
+ * @param {String} path
47
+ * @return {Promise<ImageRGBADataAsset>}
48
+ * @private
49
+ */
44
50
  async __standard(path) {
45
51
 
46
52
  const bitmap = await this.__decode_via_worker(path);
@@ -48,19 +54,19 @@ export class ImageRGBADataLoader extends AssetLoader {
48
54
 
49
55
  let data;
50
56
 
51
- switch (bitmap.bitDepth) {
52
- case 8:
57
+ const bitDepth = bitmap.bitDepth;
53
58
 
59
+ switch (bitDepth) {
60
+ case 8:
54
61
  data = new Uint8Array(bitmap.data);
55
62
  break
56
63
  case 16:
57
64
  data = new Uint16Array(bitmap.data);
58
65
  break;
59
66
  default:
60
- throw new Error(`Unsupported bit depth '${bitmap.bitDepth}'`);
67
+ throw new Error(`Unsupported bit depth '${bitDepth}'. path='${path}'`);
61
68
  }
62
69
 
63
-
64
70
  return new ImageRGBADataAsset(data, bitmap.width, bitmap.height, bitmap.itemSize);
65
71
  }
66
72
 
@@ -2,7 +2,7 @@ import { Codec } from "./Codec.js";
2
2
 
3
3
  /**
4
4
  *
5
- * @param {Image|ImageBitmap} img
5
+ * @param {Image|ImageBitmap|HTMLImageElement} img
6
6
  * @returns {Uint8Array}
7
7
  */
8
8
  function decode(img) {
@@ -28,10 +28,12 @@ export class NativeImageDecoder extends Codec {
28
28
  async decode(data) {
29
29
  const image = new Image();
30
30
 
31
+ // convert binary data to image URL that we can load
31
32
  const url = URL.createObjectURL(new Blob([data]));
32
33
 
33
34
  image.src = url;
34
35
 
36
+ // give browser a chance to decode image in async
35
37
  await image.decode();
36
38
 
37
39
  const rgba_data = decode(image);
@@ -24,6 +24,7 @@ export class ThreadedImageDecoder extends Codec {
24
24
  }
25
25
 
26
26
  async decode(data) {
27
- return await this.worker.request('decode', [data.buffer]);
27
+ const result = await this.worker.request('decode', [data.buffer]);
28
+ return result;
28
29
  }
29
30
  }
@@ -397,7 +397,6 @@ PNG.prototype.getUint8Data = function () {
397
397
 
398
398
  return {
399
399
  data,
400
- itemSize,
401
- bitDepth: this.bitDepth
400
+ itemSize
402
401
  };
403
402
  };
@@ -48,7 +48,7 @@ function isEntityTransient(entity, dataset, smComponentIndex, componentInstance)
48
48
  return isTransient;
49
49
  }
50
50
 
51
- class BinaryBufferSerialization {
51
+ class BinaryBufferSerializer {
52
52
  constructor() {
53
53
  /**
54
54
  *
@@ -171,4 +171,4 @@ class BinaryBufferSerialization {
171
171
  }
172
172
  }
173
173
 
174
- export default BinaryBufferSerialization;
174
+ export default BinaryBufferSerializer;
@@ -267,6 +267,15 @@ export class TerrainLayers {
267
267
  return index;
268
268
  }
269
269
 
270
+ /**
271
+ *
272
+ * @param {TerrainLayer} layer
273
+ * @return {boolean}
274
+ */
275
+ removeLayer(layer) {
276
+ return this.layers.removeOneOf(layer);
277
+ }
278
+
270
279
  /**
271
280
  *
272
281
  * @param {TerrainLayer} layer
@@ -159,6 +159,39 @@ export class SplatMapping {
159
159
 
160
160
  }
161
161
 
162
+ /**
163
+ *
164
+ * @param {Sampler2D} destination
165
+ * @param {number} index
166
+ * @param {number} channel
167
+ */
168
+ readLayerToSampler(destination, index, channel = 0) {
169
+ const weightData = this.weightData;
170
+
171
+ const width = this.size.x;
172
+ const height = this.size.y;
173
+
174
+ assert.equal(destination.width, width, 'destination dimensions mismatch');
175
+ assert.equal(destination.height, height, 'destination dimensions mismatch');
176
+
177
+ const dataOffset = index * width * height;
178
+
179
+ for (let y = 0; y < height; y++) {
180
+
181
+ for (let x = 0; x < width; x++) {
182
+
183
+ const targetIndex = y * width + x;
184
+ const targetAddress = dataOffset + targetIndex;
185
+
186
+ const value = weightData[targetAddress];
187
+
188
+ destination.writeChannel(x, y, channel, value);
189
+
190
+ }
191
+ }
192
+
193
+ }
194
+
162
195
  /**
163
196
  *
164
197
  * @param {Uint8Array} source
@@ -41,6 +41,26 @@ export class VertexDataSpec {
41
41
  return undefined;
42
42
  }
43
43
 
44
+ /**
45
+ * @returns {number} -1 if not found
46
+ * @param {string} name
47
+ */
48
+ getAttributeIndexByName(name) {
49
+
50
+ const attributes = this.attributes;
51
+ const n = attributes.length;
52
+
53
+ for (let i = 0; i < n; i++) {
54
+ const attribute = attributes[i];
55
+
56
+ if (attribute.name === name) {
57
+ return i;
58
+ }
59
+ }
60
+
61
+ return undefined;
62
+ }
63
+
44
64
  /**
45
65
  *
46
66
  * @param {AttributeSpec} attribute
@@ -1,9 +1,15 @@
1
1
  import {BufferGeometry} from "three";
2
2
  import {VertexDataSpec} from "../../geometry/VertexDataSpec";
3
+ import {SurfacePoint3} from "../../../../core/geom/3d/SurfacePoint3";
3
4
 
4
5
  export class MicronGeometry {
5
6
  vertex_spec: VertexDataSpec
6
7
  public proxy: BufferGeometry
7
8
 
8
9
  initialize(): void
10
+
11
+ raycast(
12
+ origin_x: number, origin_y: number, origin_z: number,
13
+ direction_x: number, direction_y: number, direction_z: number
14
+ ): SurfacePoint3[]
9
15
  }
@@ -1,5 +1,8 @@
1
1
  import { VertexDataSpec } from "../../geometry/VertexDataSpec.js";
2
2
  import { assert } from "../../../../core/assert.js";
3
+ import { intersectRay } from "../../../../core/bvh2/aabb3/AABB3Math.js";
4
+ import { computeTriangleRayIntersection } from "../../../../core/geom/3d/triangle/computeTriangleRayIntersection.js";
5
+ import { SurfacePoint3 } from "../../../../core/geom/3d/SurfacePoint3.js";
3
6
 
4
7
  let id_counter = 0;
5
8
 
@@ -55,6 +58,151 @@ export class MicronGeometry {
55
58
  this.__proxy = null;
56
59
  }
57
60
 
61
+ /**
62
+ *
63
+ * @param {number} origin_x
64
+ * @param {number} origin_y
65
+ * @param {number} origin_z
66
+ * @param {number} direction_x
67
+ * @param {number} direction_y
68
+ * @param {number} direction_z
69
+ * @returns {SurfacePoint3[]}
70
+ */
71
+ raycast(
72
+ origin_x, origin_y, origin_z,
73
+ direction_x, direction_y, direction_z
74
+ ) {
75
+
76
+ /**
77
+ *
78
+ * @type {SurfacePoint3[]}
79
+ */
80
+ const hits = [];
81
+
82
+ let stack_cursor = 1;
83
+ const stack = [this.root];
84
+
85
+ const spec = this.vertex_spec;
86
+
87
+ const position_attribute_index = spec.getAttributeIndexByName('position');
88
+
89
+ // check that position attribute actually exists
90
+ assert.isNonNegativeInteger(position_attribute_index, 'position_attribute_index');
91
+
92
+ const temp_hit = new SurfacePoint3();
93
+
94
+ while (stack_cursor > 0) {
95
+ stack_cursor--;
96
+
97
+ const patch = stack[stack_cursor];
98
+
99
+ // using group bounding box because it's conservative, as we want to be able to hit LOD_0
100
+ const bb = patch.group_bounding_box;
101
+
102
+ const bb_intersection_exists = intersectRay(
103
+ bb[0], bb[1], bb[2], bb[3], bb[4], bb[5],
104
+ origin_x, origin_y, origin_z,
105
+ direction_x, direction_y, direction_z
106
+ );
107
+
108
+ if (!bb_intersection_exists) {
109
+ // no intersection
110
+ continue;
111
+ }
112
+
113
+ if (patch.lod === 0) {
114
+ // LOD 0 - source geometry
115
+
116
+ // raycast against geometry
117
+ const indices = patch.face_indices;
118
+ const index_count = indices.length;
119
+
120
+ const vertices = patch.vertex_attribute_arrays[position_attribute_index];
121
+
122
+ for (let i = 0; i < index_count;) {
123
+ const a = indices[i++];
124
+ const b = indices[i++];
125
+ const c = indices[i++];
126
+
127
+
128
+ const a_address = a * 3;
129
+ const b_address = b * 3;
130
+ const c_address = c * 3;
131
+
132
+
133
+ const ax = vertices[a_address];
134
+ const ay = vertices[a_address + 1];
135
+ const az = vertices[a_address + 2];
136
+
137
+ const bx = vertices[b_address];
138
+ const by = vertices[b_address + 1];
139
+ const bz = vertices[b_address + 2];
140
+
141
+ const cx = vertices[c_address];
142
+ const cy = vertices[c_address + 1];
143
+ const cz = vertices[c_address + 2];
144
+
145
+ if (computeTriangleRayIntersection(
146
+ temp_hit,
147
+ origin_x, origin_y, origin_z,
148
+ direction_x, direction_y, direction_z,
149
+ ax, ay, az,
150
+ bx, by, bz,
151
+ cx, cy, cz
152
+ )) {
153
+
154
+ const contact = new SurfacePoint3();
155
+
156
+ contact.copy(temp_hit);
157
+
158
+ hits.push(contact);
159
+
160
+ }
161
+ }
162
+
163
+ } else {
164
+ // refine more
165
+ const children = patch.children;
166
+
167
+ const child_count = children.length;
168
+
169
+ for (let i = 0; i < child_count; i++) {
170
+ const child = children[i];
171
+
172
+ // push to stack
173
+ stack[stack_cursor] = child;
174
+
175
+ stack_cursor++;
176
+ }
177
+ }
178
+ }
179
+
180
+ return hits;
181
+ }
182
+
183
+ /**
184
+ *
185
+ * @param {number} lod
186
+ * @returns {number}
187
+ */
188
+ computeLodFaceCount(lod) {
189
+ let r = 0;
190
+
191
+ const patches = this.patches;
192
+ const patch_count = patches.length;
193
+ for (let i = 0; i < patch_count; i++) {
194
+ const patch = patches[i];
195
+
196
+ if (patch.lod !== lod) {
197
+ continue;
198
+ }
199
+
200
+ r += patch.polygon_count;
201
+ }
202
+
203
+ return r;
204
+ }
205
+
58
206
  get patches() {
59
207
  return this.__patches;
60
208
  }
@@ -84,17 +232,21 @@ export class MicronGeometry {
84
232
 
85
233
  /**
86
234
  * Build geometry proxy from the patches
87
- * @param {number} percent percentage of the original geometry to keep
235
+ * @param {number} fraction percentage of the original geometry to keep
236
+ * @param {number} min minimum number of triangles to keep, this will be respected first before percentage value
88
237
  */
89
- buildProxy(percent) {
238
+ buildProxy(fraction, min) {
90
239
  throw new Error('Not Implemented');
91
240
  }
92
241
 
93
242
  computeByteSize() {
94
243
  let result = 0;
95
244
 
96
- for (let i = 0; i < this.__patches.length; i++) {
97
- result += this.__patches[i].computeByteSize();
245
+ const patches = this.__patches;
246
+ const patch_count = patches.length;
247
+
248
+ for (let i = 0; i < patch_count; i++) {
249
+ result += patches[i].computeByteSize();
98
250
  }
99
251
 
100
252
  return result;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "productName": "Meep",
6
6
  "description": "production-ready JavaScript game engine based on Entity Component System Architecture",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.34.1",
8
+ "version": "2.34.5",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",
@@ -0,0 +1,350 @@
1
+ import { EngineHarness } from "../../engine/EngineHarness.js";
2
+ import EmptyView from "../../view/elements/EmptyView.js";
3
+ import { EngineConfiguration } from "../../engine/EngineConfiguration.js";
4
+ import { buildCubeURLs } from "../../engine/graphics/texture/cubemap/buildCubeURLs.js";
5
+ import { ArrayBufferLoader } from "../../engine/asset/loaders/ArrayBufferLoader.js";
6
+ import { TerrainFlags } from "../../engine/ecs/terrain/ecs/TerrainFlags.js";
7
+ import Signal from "../../core/events/signal/Signal.js";
8
+ import { NativeListController } from "../../view/controller/controls/NativeListController.js";
9
+ import { TerrainLayer } from "../../engine/ecs/terrain/ecs/layers/TerrainLayer.js";
10
+ import CheckersTextureURI from "../../engine/graphics/texture/CheckersTextureURI.js";
11
+ import { obtainTerrain } from "../../engine/ecs/terrain/util/obtainTerrain.js";
12
+ import { Cache } from "../../core/cache/Cache.js";
13
+ import { computeStringHash } from "../../core/primitives/strings/computeStringHash.js";
14
+ import { noop, strictEquals } from "../../core/function/Functions.js";
15
+ import { scaleSampler2D } from "../../engine/graphics/texture/sampler/scaleSampler2D.js";
16
+ import { Sampler2D } from "../../engine/graphics/texture/sampler/Sampler2D.js";
17
+ import { DataType } from "../../core/collection/table/DataType.js";
18
+ import { compute_typed_array_constructor_from_data_type } from "../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
19
+ import { copy_Sampler2D_channel_data } from "../../engine/graphics/texture/sampler/copy_Sampler2D_channel_data.js";
20
+ import { TextureAssetLoader } from "../../engine/asset/loaders/texture/TextureAssetLoader.js";
21
+ import { CanvasView } from "../../view/elements/CanvasView.js";
22
+ import convertSampler2D2Canvas from "../../engine/graphics/texture/sampler/Sampler2D2Canvas.js";
23
+
24
+ const engineHarness = new EngineHarness();
25
+
26
+ /**
27
+ *
28
+ * @param {Engine} engine
29
+ */
30
+ function makeConfig(engine) {
31
+
32
+ const config = new EngineConfiguration();
33
+
34
+ config.addLoader('arraybuffer', new ArrayBufferLoader());
35
+ config.addLoader('texture', new TextureAssetLoader());
36
+
37
+ return config;
38
+ }
39
+
40
+ class EditorTextureSlot {
41
+ constructor() {
42
+ this.onChanged = new Signal();
43
+
44
+ this.sampler = null;
45
+
46
+ this.__read = noop;
47
+ this.__write = noop;
48
+
49
+ /**
50
+ *
51
+ * @type {number}
52
+ */
53
+ this.itemSize = 1;
54
+ }
55
+
56
+ read() {
57
+ this.__read(this.sampler);
58
+
59
+ this.onChanged.send0();
60
+ }
61
+
62
+ write() {
63
+ this.__write(this.sampler);
64
+ }
65
+
66
+ /**
67
+ *
68
+ * @param {(Sampler2D)=>any} read
69
+ * @param {(Sampler2D)=>any} write
70
+ * @param {number} [itemSize]
71
+ * @param {DataType} [dataType]
72
+ * @return {EditorTextureSlot}
73
+ */
74
+ static from({ read, write, itemSize = 1, dataType = DataType.Uint8 }) {
75
+ const r = new EditorTextureSlot();
76
+
77
+ r.__read = read;
78
+ r.__write = write;
79
+
80
+ const TA = compute_typed_array_constructor_from_data_type(dataType);
81
+
82
+ r.sampler = new Sampler2D(new TA(itemSize), itemSize, 1, 1);
83
+
84
+ return r;
85
+ }
86
+ }
87
+
88
+ class TextureLayerEditor {
89
+ constructor() {
90
+ this.index = 0;
91
+
92
+ /**
93
+ *
94
+ * @type {Terrain|null}
95
+ * @private
96
+ */
97
+ this.__terrain = null;
98
+
99
+ this.__splat = EditorTextureSlot.from({
100
+ read: (target) => {
101
+ const terrain = this.__terrain;
102
+
103
+ target.resize(terrain.splat.size.x, terrain.splat.size.y)
104
+
105
+ terrain.splat.readLayerToSampler(target, this.index, 0);
106
+ },
107
+ write: (source) => {
108
+ this.__terrain.splat.writeLayerFromSampler(source, this.index, 0);
109
+ },
110
+ itemSize: 1
111
+ });
112
+ this.__diffuse = EditorTextureSlot.from({
113
+ read: (target) => {
114
+
115
+ const layers = this.__terrain.layers;
116
+
117
+ const layer = layers.get(this.index);
118
+
119
+ target.resize(layer.diffuse.width, layer.diffuse.height);
120
+ copy_Sampler2D_channel_data(layer.diffuse, target);
121
+ },
122
+ write: (source) => {
123
+ const layer = this.__terrain.layers.get(this.index);
124
+
125
+ copy_Sampler2D_channel_data(source, layer.diffuse);
126
+
127
+ this.__terrain.layers.writeLayerDataIntoTexture(this.index);
128
+ },
129
+ itemSize: 3
130
+ });
131
+ }
132
+
133
+ /**
134
+ * @param {Terrain} t
135
+ */
136
+ set terrain(t) {
137
+ this.__terrain = t;
138
+ }
139
+
140
+ init() {
141
+ this.__splat.read();
142
+ this.__diffuse.read();
143
+ }
144
+ }
145
+
146
+ /**
147
+ *
148
+ * @param {EditorTextureSlot} slot
149
+ */
150
+ function makeTextureSlotView({ slot }) {
151
+
152
+ const preview = new CanvasView();
153
+ preview.size.set(64, 64);
154
+
155
+
156
+ function update() {
157
+ convertSampler2D2Canvas(slot.sampler, 1, 0, preview.el);
158
+ }
159
+
160
+ preview.on.linked.add(update);
161
+ preview.bindSignal(slot.onChanged, update);
162
+
163
+
164
+ return preview;
165
+ }
166
+
167
+ /**
168
+ *
169
+ * @param {View} root
170
+ * @param {Terrain} terrain
171
+ * @param {Engine} engine
172
+ */
173
+ function makeTerrainEditor(root, terrain, engine) {
174
+ /**
175
+ *
176
+ * @type {Cache<string, Sampler2D>}
177
+ */
178
+ const PREVIEW_CACHE = new Cache({
179
+ keyHashFunction: computeStringHash,
180
+ keyEqualityFunction: strictEquals
181
+ });
182
+
183
+ const PREVIEW_SIZE = 64;
184
+
185
+ /**
186
+ *
187
+ * @param {string} url
188
+ * @return {Promise<Sampler2D>}
189
+ */
190
+ async function getPreviewFromURL(url) {
191
+ if (PREVIEW_CACHE.contains(url)) {
192
+ return PREVIEW_CACHE.get(url);
193
+ }
194
+
195
+ const asset = await engine.assetManager.promise(url, 'image');
196
+
197
+ // check cache again, might have been loaded in the meanwhile
198
+ if (PREVIEW_CACHE.contains(url)) {
199
+ return PREVIEW_CACHE.get(url);
200
+ }
201
+
202
+ const source = asset.create();
203
+
204
+ const preview = Sampler2D.uint8(4, PREVIEW_SIZE, PREVIEW_SIZE);
205
+
206
+ scaleSampler2D(source, preview);
207
+
208
+ PREVIEW_CACHE.put(url, preview);
209
+
210
+ return preview;
211
+ }
212
+
213
+ /**
214
+ *
215
+ * @type {EditorTextureSlot|null}
216
+ */
217
+ let active_slot = null;
218
+
219
+ function rebuild() {
220
+ // rebuild terrain
221
+ terrain.clearFlag(TerrainFlags.Built);
222
+ terrain.build(engine.assetManager);
223
+ }
224
+
225
+ function build_splat_editor() {
226
+ /**
227
+ *
228
+ * @type {Map<TerrainLayer, TextureLayerEditor>}
229
+ */
230
+ const editors = new Map();
231
+
232
+ return new NativeListController({
233
+ model: terrain.layers.layers,
234
+ elementFactory() {
235
+ return TerrainLayer.from(CheckersTextureURI, 1, 1);
236
+ },
237
+ /**
238
+ *
239
+ * @param {TerrainLayer} layer
240
+ */
241
+ elementViewFactory(layer) {
242
+ const e = new TextureLayerEditor();
243
+
244
+ editors.set(layer, e);
245
+
246
+ const layer_index = terrain.layers.layers.indexOf(layer);
247
+
248
+ e.terrain = terrain;
249
+ e.index = layer_index;
250
+
251
+
252
+ e.init();
253
+
254
+ const view = new EmptyView();
255
+
256
+
257
+ view.addChild(makeTextureSlotView({
258
+ slot: e.__diffuse
259
+ }));
260
+ view.addChild(makeTextureSlotView({
261
+ slot: e.__splat
262
+ }));
263
+
264
+ view.bindSignal(layer.onChanged, e.__diffuse.read, e.__diffuse);
265
+
266
+ return view;
267
+ },
268
+ operationAdd(list, el) {
269
+ terrain.layers.addLayer(el);
270
+ terrain.splat.addWeightLayer();
271
+ },
272
+ operationRemove(list, el) {
273
+ const index = terrain.layers.layers.indexOf(el);
274
+ terrain.layers.removeLayer(el);
275
+ terrain.splat.removeWeightLayer(index);
276
+
277
+ editors.delete(el);
278
+
279
+ // re-shuffle remaining editors
280
+
281
+ for (const [layer, editor] of editors) {
282
+ if (editor.index > index) {
283
+ editor.index--;
284
+ editor.init();
285
+ }
286
+ }
287
+ }
288
+ });
289
+ }
290
+
291
+ root.addChild(build_splat_editor());
292
+ }
293
+
294
+ /**
295
+ *
296
+ * @param {Engine} engine
297
+ * @return {string}
298
+ */
299
+ async function main(engine) {
300
+
301
+ //disable drag and drop on game canvas
302
+ engine.graphics.domElement.addEventListener('dragover', (e) => e.preventDefault());
303
+ engine.graphics.domElement.addEventListener('drop', (e) => e.preventDefault());
304
+
305
+
306
+ EngineHarness.buildLights({ engine });
307
+ const camera = EngineHarness.buildCamera({ engine });
308
+ EngineHarness.buildOrbitalCameraController({ engine, cameraEntity: camera.entity })
309
+
310
+ await EngineHarness.buildTerrain({ engine });
311
+
312
+ const image = await engine.assetManager.promise("diffuseMap1.png", 'image');
313
+
314
+ console.log(image.create());
315
+
316
+ const vMain = new EmptyView({ classList: ['ui-texture-testing-tool-view'] });
317
+
318
+ vMain.css({
319
+ position: "absolute",
320
+ left: "0",
321
+ top: "0",
322
+ pointerEvents: "initial"
323
+ });
324
+
325
+ makeTerrainEditor(vMain, obtainTerrain(engine.entityManager.dataset), engine);
326
+
327
+
328
+ document.body.appendChild(vMain.el);
329
+ vMain.link();
330
+ }
331
+
332
+
333
+ /**
334
+ *
335
+ * @param {EngineHarness} harness
336
+ */
337
+ async function init(harness) {
338
+
339
+ const engine = harness.engine;
340
+
341
+ await makeConfig(engine).apply(engine);
342
+
343
+ await engine.graphics.loadEnvironmentMap(buildCubeURLs('data/textures/cubemaps/hip_miramar/32/', '.png'));
344
+
345
+ await harness.initialize();
346
+
347
+ main(engine);
348
+ }
349
+
350
+ init(engineHarness);
@@ -27,8 +27,8 @@ export class NativeListController extends View {
27
27
  /**
28
28
  * @template T
29
29
  * @param {List<T>} model
30
- * @param {function} elementViewFactory
31
- * @param {function} elementFactory
30
+ * @param {(T)=>View} elementViewFactory
31
+ * @param {()=>T} elementFactory
32
32
  * @param {string[]} [classList]
33
33
  * @param {function(List<T>, T)} [operationAdd] Allows user to supply a special operation for adding an element to the list
34
34
  * @param {function(List<T>, T)} [operationRemove] Allows user to supply a special operation for removing an element from the list
@@ -43,7 +43,7 @@ export class NativeListController extends View {
43
43
  }) {
44
44
  super();
45
45
 
46
- assert.isFunction(elementViewFactory,'elementViewFactory');
46
+ assert.isFunction(elementViewFactory, 'elementViewFactory');
47
47
 
48
48
  this.el = document.createElement('div');
49
49
 
@@ -55,6 +55,9 @@ export class NativeListController extends View {
55
55
  elementFactory(el) {
56
56
  const elementView = elementViewFactory(el);
57
57
 
58
+ assert.defined(elementView, 'elementView');
59
+ assert.equal(elementView.isView, true, 'elementView.isView !== true');
60
+
58
61
  const vWrapper = new EmptyView({ classList: ['element-wrapper'] });
59
62
 
60
63
  elementView.addClass('wrapped-element');
@@ -1,32 +0,0 @@
1
- import { Sampler2D } from "../Sampler2D.js";
2
- import { scaleSampler2D } from "../scaleSampler2D.js";
3
- import convertSampler2D2Canvas from "../Sampler2D2Canvas.js";
4
- import { typedArrayConstructorByInstance } from "../typedArrayConstructorByInstance.js";
5
-
6
- /**
7
- *
8
- * @param {Sampler2D} s
9
- * @param {number} x
10
- * @param {number} y
11
- * @param scale
12
- * @param offset
13
- * @param {number} resolution
14
- */
15
- export function paintSamplerOnHTML(s, x, y, scale, offset, resolution=256) {
16
-
17
- const d = resolution;
18
-
19
- const TA = typedArrayConstructorByInstance(s.data);
20
-
21
- const target = new Sampler2D(new TA(d * d * s.itemSize), s.itemSize, d, d);
22
-
23
- scaleSampler2D(s, target);
24
-
25
- const c = convertSampler2D2Canvas(target, scale, offset);
26
- c.style.zIndex = 1000;
27
- c.style.position = "absolute";
28
- c.style.left = `${x}px`;
29
- c.style.top = `${y}px`;
30
-
31
- document.body.appendChild(c);
32
- }