@woosh/meep-engine 2.39.38 → 2.39.41
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.
- package/core/binary/Base64.js +58 -31
- package/core/binary/Base64.spec.js +14 -0
- package/core/binary/operations/ceilPowerOfTwo.spec.js +17 -0
- package/core/bvh2/binary/2/BinaryUint32BVH.js +7 -1
- package/core/bvh2/binary/2/BinaryUint32BVH.spec.js +31 -1
- package/core/bvh2/bvh3/bvh_query_user_data_nearest_to_point.js +5 -5
- package/core/bvh2/bvh3/bvh_query_user_data_nearest_to_point.spec.js +70 -0
- package/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.spec.js +2 -2
- package/core/collection/IteratorUtils.js +1 -0
- package/core/collection/queue/Deque.js +5 -2
- package/core/color/Color.js +29 -7
- package/core/color/hsluv/HSLuv.js +187 -0
- package/core/geom/3d/aabb/aabb3_matrix4_project.js +1 -0
- package/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +1 -1
- package/core/geom/Quaternion.js +52 -38
- package/core/model/ModuleRegistry.js +1 -1
- package/core/model/reactive/model/terminal/ReactiveReference.js +1 -1
- package/core/model/reactive/trigger/ReactiveTrigger.js +14 -4
- package/core/primitives/strings/compareStrings.js +22 -0
- package/editor/Editor.js +2 -0
- package/editor/ecs/component/editors/ImagePathEditor.js +83 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainEditor.js +12 -6
- package/editor/tools/v2/BlenderCameraOrientationGizmo.js +22 -11
- package/engine/EngineHarness.js +7 -0
- package/engine/asset/loaders/geometry/geometry/computeBufferAttributeHash.js +5 -6
- package/engine/asset/loaders/image/codec/Codec.js +9 -0
- package/engine/asset/loaders/image/codec/CodecWithFallback.js +52 -11
- package/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +12 -0
- package/engine/asset/loaders/image/png/PNGReader.js +2 -1
- package/engine/asset/loaders/image/png/PNG_HEADER_BYTES.js +1 -0
- package/engine/computeStridedIntegerArrayHash.js +19 -0
- package/engine/ecs/EntityBuilder.d.ts +2 -0
- package/engine/ecs/gui/GUIElement.d.ts +3 -1
- package/engine/ecs/terrain/ecs/layers/TerrainLayers.js +5 -3
- package/engine/ecs/terrain/ecs/splat/SplatMapping.js +27 -4
- package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +11 -2
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +14 -6
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +2 -8
- package/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +2 -1
- package/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +17 -2
- package/engine/graphics/geometry/optimization/merge/merge_geometry_hierarchy.js +336 -0
- package/engine/graphics/geometry/optimization/merge/prototypeGeometryMerge.js +176 -0
- package/engine/graphics/micron/build/hierarchy/buildAbstractPatchHierarchy.js +7 -3
- package/engine/graphics/micron/build/hierarchy/merge_patches.js +0 -1
- package/engine/graphics/micron/prototypeVirtualGeometry.js +3 -3
- package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +32 -1
- package/engine/graphics/render/forward_plus/LightManager.js +58 -13
- package/engine/graphics/render/forward_plus/debug/createScreenGrid.js +192 -9
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +42 -1
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +1 -0
- package/engine/graphics/render/forward_plus/materials/ForwardPlusThreeMaterial.js +5 -0
- package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +1 -4
- package/engine/graphics/render/forward_plus/model/Decal.js +33 -5
- package/engine/graphics/render/forward_plus/model/PointLight.js +1 -1
- package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +4 -0
- package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +480 -12
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +49 -29
- package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +11 -0
- package/engine/graphics/texture/atlas/CachingTextureAtlas.js +34 -0
- package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +9 -1
- package/engine/graphics/texture/atlas/TextureAtlas.js +29 -16
- package/engine/graphics/texture/atlas/TextureAtlasDebugger.js +75 -19
- package/engine/graphics/texture/sampler/Sampler2D.d.ts +2 -0
- package/engine/graphics/texture/sampler/Sampler2D.js +72 -11
- package/engine/sound/ecs/SoundListenerSystem.js +5 -0
- package/engine/sound/ecs/emitter/SoundEmitter.js +12 -1
- package/package.json +1 -1
- package/view/elements/button/ButtonView.js +12 -1
- package/view/tooltip/TooltipManager.js +0 -95
|
@@ -10,6 +10,48 @@ import { BVH_BINARY_NODE_SIZE, BVH_LEAF_NODE_SIZE } from "../../../../../core/bv
|
|
|
10
10
|
*/
|
|
11
11
|
const stack = [];
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @param {DataView} data_view
|
|
16
|
+
* @param {number} address
|
|
17
|
+
* @param {ArrayLike<number>|number[]} planes
|
|
18
|
+
* @return {boolean}
|
|
19
|
+
*/
|
|
20
|
+
function frustum_check(data_view, address, planes) {
|
|
21
|
+
const n_x0 = data_view.getFloat32(address);
|
|
22
|
+
const n_y0 = data_view.getFloat32(address + 4);
|
|
23
|
+
const n_z0 = data_view.getFloat32(address + 8);
|
|
24
|
+
const n_x1 = data_view.getFloat32(address + 12);
|
|
25
|
+
const n_y1 = data_view.getFloat32(address + 16);
|
|
26
|
+
const n_z1 = data_view.getFloat32(address + 20);
|
|
27
|
+
|
|
28
|
+
for (let plane_address = 0; plane_address < 24; plane_address += 4) {
|
|
29
|
+
|
|
30
|
+
const plane_normal_x = planes[plane_address];
|
|
31
|
+
const plane_normal_y = planes[plane_address + 1];
|
|
32
|
+
const plane_normal_z = planes[plane_address + 2];
|
|
33
|
+
const plane_constant = planes[plane_address + 3];
|
|
34
|
+
|
|
35
|
+
const distanceAbovePlane = aabb3_computeDistanceAbovePlane_max(
|
|
36
|
+
plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
|
|
37
|
+
n_x0, n_y0, n_z0,
|
|
38
|
+
n_x1, n_y1, n_z1
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
if (distanceAbovePlane <= 0) {
|
|
42
|
+
// node is below the plane
|
|
43
|
+
|
|
44
|
+
// query_bvh_frustum_from_objects.rejection_count++;
|
|
45
|
+
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// TODO under current scheme we can reserve 6 bit in what we push onto the stack for plane mask (allows us to skip some planar tests)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
13
55
|
/**
|
|
14
56
|
* Most of the data is in flat continuous array for cache coherence
|
|
15
57
|
* @param {number[]} destination
|
|
@@ -57,35 +99,8 @@ export function query_bvh_frustum_from_texture(
|
|
|
57
99
|
// is intermediate node
|
|
58
100
|
const node_address = node_index * BVH_BINARY_NODE_SIZE;
|
|
59
101
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const n_z0 = data_view.getFloat32(node_address + 8);
|
|
63
|
-
const n_x1 = data_view.getFloat32(node_address + 12);
|
|
64
|
-
const n_y1 = data_view.getFloat32(node_address + 16);
|
|
65
|
-
const n_z1 = data_view.getFloat32(node_address + 20);
|
|
66
|
-
|
|
67
|
-
for (plane_address = 0; plane_address < 24; plane_address += 4) {
|
|
68
|
-
|
|
69
|
-
const plane_normal_x = planes[plane_address];
|
|
70
|
-
const plane_normal_y = planes[plane_address + 1];
|
|
71
|
-
const plane_normal_z = planes[plane_address + 2];
|
|
72
|
-
const plane_constant = planes[plane_address + 3];
|
|
73
|
-
|
|
74
|
-
const distanceAbovePlane = aabb3_computeDistanceAbovePlane_max(
|
|
75
|
-
plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
|
|
76
|
-
n_x0, n_y0, n_z0,
|
|
77
|
-
n_x1, n_y1, n_z1
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
if (distanceAbovePlane < 0) {
|
|
81
|
-
// node is below the plane
|
|
82
|
-
|
|
83
|
-
// query_bvh_frustum_from_objects.rejection_count++;
|
|
84
|
-
|
|
85
|
-
continue stack_loop;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// TODO under current scheme we can reserve 6 bit in what we push onto the stack for plane mask (allows us to skip some planar tests)
|
|
102
|
+
if (!frustum_check(data_view, node_address, planes)) {
|
|
103
|
+
continue;
|
|
89
104
|
}
|
|
90
105
|
|
|
91
106
|
const left_index = (node_index << 1) + 1;
|
|
@@ -130,6 +145,11 @@ export function query_bvh_frustum_from_texture(
|
|
|
130
145
|
|
|
131
146
|
} else if (light_type === 3) {
|
|
132
147
|
// decal
|
|
148
|
+
|
|
149
|
+
if (!frustum_check(data_view, node_address, planes)) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
133
153
|
} else {
|
|
134
154
|
throw new Error(`Unsupported light type ${light_type}`);
|
|
135
155
|
}
|
|
@@ -16,4 +16,15 @@ export class AbstractTextureAtlas {
|
|
|
16
16
|
remove(patch) {
|
|
17
17
|
throw new Error('Not Implemented')
|
|
18
18
|
}
|
|
19
|
+
|
|
20
|
+
get sampler() {
|
|
21
|
+
throw new Error('Not Implemented')
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @throws {Error} if update fails
|
|
26
|
+
*/
|
|
27
|
+
update() {
|
|
28
|
+
throw new Error('Not Implemented')
|
|
29
|
+
}
|
|
19
30
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Cache } from "../../../../core/cache/Cache.js";
|
|
2
2
|
import { AbstractTextureAtlas } from "./AbstractTextureAtlas.js";
|
|
3
|
+
import { invokeObjectHash } from "../../../../core/model/object/invokeObjectHash.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* 4Mb
|
|
@@ -26,6 +27,7 @@ export class CachingTextureAtlas extends AbstractTextureAtlas {
|
|
|
26
27
|
*/
|
|
27
28
|
this.__cached_patches = new Cache({
|
|
28
29
|
maxWeight: cache_size,
|
|
30
|
+
keyHashFunction: invokeObjectHash,
|
|
29
31
|
keyWeigher(sampler) {
|
|
30
32
|
return sampler.computeByteSize();
|
|
31
33
|
}
|
|
@@ -41,6 +43,25 @@ export class CachingTextureAtlas extends AbstractTextureAtlas {
|
|
|
41
43
|
this.__cached_patches.onEvicted.add(this.__handle_cache_eviction, this);
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
update() {
|
|
47
|
+
try {
|
|
48
|
+
this.__atals.update();
|
|
49
|
+
} catch (e) {
|
|
50
|
+
if (this.__cached_patches.size() > 0) {
|
|
51
|
+
|
|
52
|
+
// has some caches patches, lets drop them
|
|
53
|
+
this.__cached_patches.clear();
|
|
54
|
+
|
|
55
|
+
// try to update again
|
|
56
|
+
this.__atals.update();
|
|
57
|
+
|
|
58
|
+
} else {
|
|
59
|
+
// just re-throw
|
|
60
|
+
throw e;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
44
65
|
/**
|
|
45
66
|
*
|
|
46
67
|
* @returns {AbstractTextureAtlas}
|
|
@@ -49,6 +70,14 @@ export class CachingTextureAtlas extends AbstractTextureAtlas {
|
|
|
49
70
|
return this.__atals;
|
|
50
71
|
}
|
|
51
72
|
|
|
73
|
+
/**
|
|
74
|
+
*
|
|
75
|
+
* @return {Sampler2D}
|
|
76
|
+
*/
|
|
77
|
+
get sampler() {
|
|
78
|
+
return this.__atals.sampler;
|
|
79
|
+
}
|
|
80
|
+
|
|
52
81
|
/**
|
|
53
82
|
*
|
|
54
83
|
* @param {Sampler2D} sampler
|
|
@@ -74,6 +103,11 @@ export class CachingTextureAtlas extends AbstractTextureAtlas {
|
|
|
74
103
|
|
|
75
104
|
if (existing_patch !== null) {
|
|
76
105
|
// cache hit
|
|
106
|
+
|
|
107
|
+
// remove from cache
|
|
108
|
+
this.__cached_patches.remove(sampler);
|
|
109
|
+
|
|
110
|
+
// return patch
|
|
77
111
|
return existing_patch;
|
|
78
112
|
}
|
|
79
113
|
|
|
@@ -26,6 +26,10 @@ export class ReferencedTextureAtlas extends AbstractTextureAtlas {
|
|
|
26
26
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
update() {
|
|
30
|
+
this.__atlas.update();
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
/**
|
|
30
34
|
*
|
|
31
35
|
* @param {Reference} ref
|
|
@@ -39,8 +43,10 @@ export class ReferencedTextureAtlas extends AbstractTextureAtlas {
|
|
|
39
43
|
ref_counts.set(patch, ref_count - 1);
|
|
40
44
|
|
|
41
45
|
if (ref_count === 1) {
|
|
42
|
-
// clear patch
|
|
46
|
+
// last reference removed, clear patch
|
|
43
47
|
this.__atlas.remove(patch);
|
|
48
|
+
ref_counts.delete(patch);
|
|
49
|
+
this.__patches.delete(patch.sampler);
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
|
|
@@ -61,6 +67,8 @@ export class ReferencedTextureAtlas extends AbstractTextureAtlas {
|
|
|
61
67
|
if (patch === undefined) {
|
|
62
68
|
patch = atlas.add(sampler);
|
|
63
69
|
ref_counts.set(patch, 1)
|
|
70
|
+
|
|
71
|
+
this.__patches.set(sampler, patch);
|
|
64
72
|
} else {
|
|
65
73
|
ref_counts.set(patch, ref_counts.get(patch) + 1);
|
|
66
74
|
}
|
|
@@ -9,7 +9,9 @@ import { AtlasPatchFlag } from "./AtlasPatchFlag.js";
|
|
|
9
9
|
import Signal from "../../../../core/events/signal/Signal.js";
|
|
10
10
|
import { assert } from "../../../../core/assert.js";
|
|
11
11
|
import { DataType } from "../../../../core/collection/table/DataType.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
DataType2TypedArrayConstructorMapping
|
|
14
|
+
} from "../../../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
|
|
13
15
|
import { AbstractTextureAtlas } from "./AbstractTextureAtlas.js";
|
|
14
16
|
import { invokeObjectClone } from "../../../../core/model/object/invokeObjectClone.js";
|
|
15
17
|
|
|
@@ -47,10 +49,11 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
47
49
|
const channel_count = 4;
|
|
48
50
|
|
|
49
51
|
/**
|
|
52
|
+
* @private
|
|
50
53
|
* @readonly
|
|
51
54
|
* @type {Sampler2D}
|
|
52
55
|
*/
|
|
53
|
-
this.
|
|
56
|
+
this.__sampler = new Sampler2D(new TypeArrayConstructor(size * size * channel_count), channel_count, size, size);
|
|
54
57
|
|
|
55
58
|
|
|
56
59
|
/**
|
|
@@ -71,6 +74,14 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
71
74
|
this.__needsUpdate = false;
|
|
72
75
|
}
|
|
73
76
|
|
|
77
|
+
/**
|
|
78
|
+
*
|
|
79
|
+
* @return {Sampler2D}
|
|
80
|
+
*/
|
|
81
|
+
get sampler() {
|
|
82
|
+
return this.__sampler;
|
|
83
|
+
}
|
|
84
|
+
|
|
74
85
|
/**
|
|
75
86
|
*
|
|
76
87
|
* @param {Sampler2D} sampler
|
|
@@ -127,7 +138,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
127
138
|
|
|
128
139
|
|
|
129
140
|
//erase data
|
|
130
|
-
this.
|
|
141
|
+
this.__sampler.data.fill(0);
|
|
131
142
|
|
|
132
143
|
this.__needsUpdate = true;
|
|
133
144
|
}
|
|
@@ -175,7 +186,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
175
186
|
|
|
176
187
|
this.size.set(x, y);
|
|
177
188
|
this.packer.resize(x, y);
|
|
178
|
-
this.
|
|
189
|
+
this.__sampler.resize(x, y);
|
|
179
190
|
|
|
180
191
|
return true;
|
|
181
192
|
}
|
|
@@ -188,17 +199,17 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
188
199
|
paintPatch(patch) {
|
|
189
200
|
// console.time('TextureAtlas.paintPatch');
|
|
190
201
|
|
|
191
|
-
const target = this.
|
|
202
|
+
const target = this.__sampler;
|
|
192
203
|
|
|
193
204
|
const source = patch.sampler;
|
|
194
205
|
|
|
195
|
-
const
|
|
196
|
-
const
|
|
206
|
+
const patch_position = patch.position;
|
|
207
|
+
const patch_size = patch.size;
|
|
197
208
|
|
|
198
209
|
target.copy_sameItemSize(
|
|
199
210
|
source,
|
|
200
211
|
0, 0,
|
|
201
|
-
|
|
212
|
+
patch_position.x, patch_position.y, patch_size.x, patch_size.y
|
|
202
213
|
);
|
|
203
214
|
|
|
204
215
|
patch.setFlag(AtlasPatchFlag.Painted);
|
|
@@ -222,7 +233,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
222
233
|
|
|
223
234
|
this.eraseArea(x0, y0, x1, y1);
|
|
224
235
|
|
|
225
|
-
|
|
236
|
+
// mark as non-painted
|
|
226
237
|
patch.clearFlag(AtlasPatchFlag.Painted);
|
|
227
238
|
}
|
|
228
239
|
|
|
@@ -234,9 +245,9 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
234
245
|
* @param {number} y1
|
|
235
246
|
*/
|
|
236
247
|
eraseArea(x0, y0, x1, y1) {
|
|
237
|
-
const sampler = this.
|
|
248
|
+
const sampler = this.__sampler;
|
|
238
249
|
|
|
239
|
-
sampler.zeroFill(x0, y0, x1, y1);
|
|
250
|
+
sampler.zeroFill(x0, y0, x1 - x0, y1 - y0);
|
|
240
251
|
}
|
|
241
252
|
|
|
242
253
|
/**
|
|
@@ -246,6 +257,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
246
257
|
* @return {AtlasPatch}
|
|
247
258
|
*/
|
|
248
259
|
add(sampler, padding = 4) {
|
|
260
|
+
// console.log('#add');
|
|
249
261
|
|
|
250
262
|
const patch = new AtlasPatch();
|
|
251
263
|
|
|
@@ -272,6 +284,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
272
284
|
* @return {boolean}
|
|
273
285
|
*/
|
|
274
286
|
remove(patch) {
|
|
287
|
+
// console.log('#remove');
|
|
275
288
|
const patchIndex = this.patches.indexOf(patch);
|
|
276
289
|
|
|
277
290
|
if (patchIndex === -1) {
|
|
@@ -282,15 +295,15 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
282
295
|
this.patches.splice(patchIndex, 1);
|
|
283
296
|
this.idPool.release(patch.id);
|
|
284
297
|
|
|
285
|
-
if (patch.getFlag(AtlasPatchFlag.Packed)) {
|
|
286
|
-
this.packer.remove(patch.packing);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
298
|
if (patch.getFlag(AtlasPatchFlag.Painted)) {
|
|
290
299
|
//erase the patch
|
|
291
300
|
this.erasePatch(patch);
|
|
292
301
|
}
|
|
293
302
|
|
|
303
|
+
if (patch.getFlag(AtlasPatchFlag.Packed)) {
|
|
304
|
+
this.packer.remove(patch.packing);
|
|
305
|
+
}
|
|
306
|
+
|
|
294
307
|
return true;
|
|
295
308
|
}
|
|
296
309
|
|
|
@@ -513,7 +526,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
|
|
|
513
526
|
* Drops all the data
|
|
514
527
|
*/
|
|
515
528
|
reset() {
|
|
516
|
-
this.
|
|
529
|
+
this.__sampler.data.fill(0);
|
|
517
530
|
|
|
518
531
|
this.patches = [];
|
|
519
532
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import EmptyView from "../../../../view/elements/EmptyView.js";
|
|
2
1
|
import Vector2 from "../../../../core/geom/Vector2.js";
|
|
2
|
+
import { CanvasView } from "../../../../view/elements/CanvasView.js";
|
|
3
|
+
import { FrameRunner } from "../../FrameRunner.js";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Visualizer for TextureAtlas, to help understand current state of the atlas
|
|
@@ -9,13 +10,19 @@ export class TextureAtlasDebugger {
|
|
|
9
10
|
*
|
|
10
11
|
* @param {TextureAtlas} atlas
|
|
11
12
|
* @param {Vector2} [scale]
|
|
13
|
+
* @param {boolean} [draw_padding]
|
|
14
|
+
* @param {boolean} [draw_borders]
|
|
12
15
|
*/
|
|
13
|
-
constructor(atlas, {
|
|
16
|
+
constructor(atlas, {
|
|
17
|
+
scale = new Vector2(1, 1),
|
|
18
|
+
draw_padding = true,
|
|
19
|
+
draw_borders = true
|
|
20
|
+
} = {}) {
|
|
14
21
|
window.atlas = atlas;
|
|
15
22
|
|
|
16
|
-
|
|
23
|
+
const vCanvas = new CanvasView();
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
vCanvas.css({
|
|
19
26
|
position: "absolute",
|
|
20
27
|
top: "0",
|
|
21
28
|
left: "0",
|
|
@@ -25,49 +32,98 @@ export class TextureAtlasDebugger {
|
|
|
25
32
|
background: 'rgba(0,0,0,0.8)'
|
|
26
33
|
});
|
|
27
34
|
|
|
28
|
-
const ctx =
|
|
35
|
+
const ctx = vCanvas.context2d;
|
|
36
|
+
|
|
37
|
+
let last_drawn_version = -1;
|
|
29
38
|
|
|
30
39
|
function draw() {
|
|
31
40
|
|
|
32
41
|
const size = atlas.size;
|
|
42
|
+
|
|
43
|
+
|
|
33
44
|
if (size.x !== 0 && size.y !== 0) {
|
|
34
45
|
ctx.clearRect(0, 0, size.x, size.y);
|
|
35
46
|
|
|
36
47
|
const imageData = ctx.createImageData(size.x, size.y);
|
|
48
|
+
|
|
37
49
|
imageData.data.set(atlas.sampler.data);
|
|
38
50
|
|
|
39
51
|
ctx.putImageData(imageData, 0, 0);
|
|
40
52
|
|
|
41
|
-
ctx.strokeStyle = 'red';
|
|
42
53
|
|
|
43
54
|
//draw patch boundaries
|
|
44
|
-
atlas.patches.
|
|
45
|
-
const
|
|
55
|
+
for (let i = 0; i < atlas.patches.length; i++) {
|
|
56
|
+
const patch = atlas.patches[i];
|
|
46
57
|
|
|
47
|
-
|
|
58
|
+
if (draw_padding) {
|
|
59
|
+
// draw padding area
|
|
60
|
+
ctx.strokeStyle = 'rgba(0,166,255,0.5)';
|
|
61
|
+
ctx.lineWidth = patch.padding;
|
|
48
62
|
|
|
49
|
-
|
|
63
|
+
ctx.strokeRect(
|
|
64
|
+
patch.position.x - patch.padding * 0.5,
|
|
65
|
+
patch.position.y - patch.padding * 0.5,
|
|
66
|
+
patch.size.x + patch.padding,
|
|
67
|
+
patch.size.y + patch.padding,
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (draw_borders) {
|
|
72
|
+
const aabb2 = patch.packing;
|
|
73
|
+
|
|
74
|
+
// draw patch borders
|
|
75
|
+
ctx.strokeStyle = 'red';
|
|
76
|
+
ctx.lineWidth = 1;
|
|
77
|
+
|
|
78
|
+
ctx.strokeRect(aabb2.x0, aabb2.y0, aabb2.getWidth(), aabb2.getHeight());
|
|
79
|
+
}
|
|
80
|
+
}
|
|
50
81
|
|
|
51
82
|
} else {
|
|
52
83
|
ctx.clearRect(0, 0, 1, 1);
|
|
53
84
|
}
|
|
85
|
+
|
|
86
|
+
// remember last drawn version
|
|
87
|
+
last_drawn_version = atlas.sampler.version;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
vCanvas.size.set(0, 0);
|
|
91
|
+
|
|
92
|
+
function try_draw() {
|
|
93
|
+
if (last_drawn_version !== atlas.sampler.version) {
|
|
94
|
+
draw();
|
|
95
|
+
}
|
|
54
96
|
}
|
|
55
97
|
|
|
56
|
-
|
|
98
|
+
const write_dimensions = () => {
|
|
99
|
+
const x = atlas.size.x;
|
|
100
|
+
const y = atlas.size.y;
|
|
57
101
|
|
|
58
|
-
|
|
59
|
-
|
|
102
|
+
vCanvas.size.set(x, y);
|
|
103
|
+
vCanvas.scale.copy(scale);
|
|
104
|
+
vCanvas.transformOrigin.set(0, 0);
|
|
105
|
+
};
|
|
60
106
|
|
|
61
|
-
|
|
62
|
-
|
|
107
|
+
function full_update() {
|
|
108
|
+
write_dimensions();
|
|
109
|
+
draw();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const fr = new FrameRunner(try_draw);
|
|
63
113
|
|
|
64
|
-
|
|
65
|
-
v.el.setAttribute('width', x);
|
|
66
|
-
v.el.setAttribute('height', y);
|
|
114
|
+
atlas.size.onChanged.add(full_update);
|
|
67
115
|
|
|
116
|
+
vCanvas.on.linked.add(() => {
|
|
117
|
+
full_update();
|
|
118
|
+
fr.startup();
|
|
68
119
|
});
|
|
69
120
|
|
|
70
|
-
|
|
121
|
+
vCanvas.on.unlinked.add(() => {
|
|
122
|
+
fr.shutdown();
|
|
123
|
+
})
|
|
124
|
+
|
|
71
125
|
atlas.on.painted.add(draw);
|
|
126
|
+
|
|
127
|
+
this.vAtlasContent = vCanvas;
|
|
72
128
|
}
|
|
73
129
|
}
|
|
@@ -14,6 +14,9 @@ import { typedArrayToDataType } from "../../../../core/collection/array/typedArr
|
|
|
14
14
|
import {
|
|
15
15
|
compute_typed_array_constructor_from_data_type
|
|
16
16
|
} from "../../../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
|
|
17
|
+
import { Base64 } from "../../../../core/binary/Base64.js";
|
|
18
|
+
import { computeStridedIntegerArrayHash } from "../../../computeStridedIntegerArrayHash.js";
|
|
19
|
+
import { is_typed_array_equals } from "../../../../core/collection/array/typed/is_typed_array_equals.js";
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* @class
|
|
@@ -22,20 +25,20 @@ export class Sampler2D {
|
|
|
22
25
|
/**
|
|
23
26
|
*
|
|
24
27
|
* @param {ArrayLike<number>|number[]|Uint8ClampedArray|Uint8Array|Uint16Array|Uint32Array|Int8Array|Int16Array|Int32Array|Float32Array|Float64Array} data
|
|
25
|
-
* @param {
|
|
26
|
-
* @param {
|
|
27
|
-
* @param {
|
|
28
|
+
* @param {number} itemSize
|
|
29
|
+
* @param {number} width
|
|
30
|
+
* @param {number} height
|
|
28
31
|
* @constructor
|
|
29
32
|
*/
|
|
30
33
|
constructor(data = [], itemSize = 1, width = 0, height = 0) {
|
|
31
|
-
if (!Number.isInteger(itemSize)) {
|
|
32
|
-
throw new Error(`itemSize must be integer, instead was ${itemSize}`);
|
|
34
|
+
if (!Number.isInteger(itemSize) || itemSize < 0) {
|
|
35
|
+
throw new Error(`itemSize must be a non-negative integer, instead was ${itemSize}`);
|
|
33
36
|
}
|
|
34
|
-
if (!Number.isInteger(width)) {
|
|
35
|
-
throw new Error(`width must be integer, instead was ${width}`);
|
|
37
|
+
if (!Number.isInteger(width) || itemSize < 0) {
|
|
38
|
+
throw new Error(`width must be a non-negative integer, instead was ${width}`);
|
|
36
39
|
}
|
|
37
|
-
if (!Number.isInteger(height)) {
|
|
38
|
-
throw new Error(`height must be integer, instead was ${height}`);
|
|
40
|
+
if (!Number.isInteger(height) || itemSize < 0) {
|
|
41
|
+
throw new Error(`height must be a non-negative integer, instead was ${height}`);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
if (data === undefined) {
|
|
@@ -522,6 +525,7 @@ export class Sampler2D {
|
|
|
522
525
|
* @returns {number}
|
|
523
526
|
*/
|
|
524
527
|
sampleChannelBilinear(x, y, channel) {
|
|
528
|
+
assert.isNonNegativeInteger(channel, 'channel');
|
|
525
529
|
|
|
526
530
|
const itemSize = this.itemSize;
|
|
527
531
|
|
|
@@ -1098,12 +1102,16 @@ export class Sampler2D {
|
|
|
1098
1102
|
* @param {Number} height
|
|
1099
1103
|
*/
|
|
1100
1104
|
zeroFill(x, y, width, height) {
|
|
1105
|
+
assert.isNonNegativeInteger(width, 'width');
|
|
1106
|
+
assert.isNonNegativeInteger(height, 'height');
|
|
1101
1107
|
|
|
1102
1108
|
const x0 = clamp(x, 0, this.width);
|
|
1103
1109
|
const y0 = clamp(y, 0, this.height);
|
|
1104
1110
|
const x1 = clamp(x + width, 0, this.width);
|
|
1105
1111
|
const y1 = clamp(y + height, 0, this.height);
|
|
1106
1112
|
|
|
1113
|
+
// console.log(`#zerofill x:${x}, y:${y}, width:${width}, height:${height} \t -> \t x0:${x0}, y0:${y0}, x1:${x1}, y1:${y1}`); // DEBUG
|
|
1114
|
+
|
|
1107
1115
|
const data = this.data;
|
|
1108
1116
|
const itemSize = this.itemSize;
|
|
1109
1117
|
|
|
@@ -1431,6 +1439,40 @@ export class Sampler2D {
|
|
|
1431
1439
|
}
|
|
1432
1440
|
}
|
|
1433
1441
|
|
|
1442
|
+
/**
|
|
1443
|
+
*
|
|
1444
|
+
* @param {Sampler2D} other
|
|
1445
|
+
* @return {boolean}
|
|
1446
|
+
*/
|
|
1447
|
+
equals(other) {
|
|
1448
|
+
if (
|
|
1449
|
+
this.width !== other.width
|
|
1450
|
+
|| this.height !== other.height
|
|
1451
|
+
|| this.itemSize !== other.itemSize
|
|
1452
|
+
) {
|
|
1453
|
+
return false;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
return is_typed_array_equals(this.data, other.data);
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
*
|
|
1461
|
+
* @return {number}
|
|
1462
|
+
*/
|
|
1463
|
+
hash() {
|
|
1464
|
+
let hash = (((this.width & 0xFFFF) << 16) | (this.height & 0xFFFF)) ^ this.itemSize;
|
|
1465
|
+
|
|
1466
|
+
const length = this.data.length;
|
|
1467
|
+
|
|
1468
|
+
const stride = Math.max(1, Math.ceil(length / 509));
|
|
1469
|
+
|
|
1470
|
+
hash ^= computeStridedIntegerArrayHash(this.data, 0, length, stride);
|
|
1471
|
+
|
|
1472
|
+
return hash;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
|
|
1434
1476
|
/**
|
|
1435
1477
|
* @returns {Sampler2D}
|
|
1436
1478
|
*/
|
|
@@ -1450,19 +1492,38 @@ export class Sampler2D {
|
|
|
1450
1492
|
}
|
|
1451
1493
|
|
|
1452
1494
|
toJSON() {
|
|
1495
|
+
const encoded = Base64.encode(this.data.buffer);
|
|
1496
|
+
|
|
1453
1497
|
return {
|
|
1454
1498
|
height: this.height,
|
|
1455
1499
|
width: this.width,
|
|
1456
1500
|
itemSize: this.itemSize,
|
|
1457
1501
|
type: typedArrayToDataType(this.data),
|
|
1458
|
-
data:
|
|
1502
|
+
data: encoded
|
|
1459
1503
|
}
|
|
1460
1504
|
}
|
|
1461
1505
|
|
|
1462
1506
|
fromJSON({ height, width, itemSize, type, data }) {
|
|
1463
1507
|
const CTOR = compute_typed_array_constructor_from_data_type(type);
|
|
1464
1508
|
|
|
1465
|
-
|
|
1509
|
+
if (typeof data === "string") {
|
|
1510
|
+
|
|
1511
|
+
const decoded = Base64.decode(data);
|
|
1512
|
+
|
|
1513
|
+
this.data = new CTOR(decoded);
|
|
1514
|
+
|
|
1515
|
+
} else if (Array.isArray(data)) {
|
|
1516
|
+
// deprecated
|
|
1517
|
+
console.warn('Array JSON format is deprecated, please upgrade your data as soon as possible');
|
|
1518
|
+
|
|
1519
|
+
this.data = new CTOR(data);
|
|
1520
|
+
|
|
1521
|
+
} else {
|
|
1522
|
+
|
|
1523
|
+
throw new Error('Unsupported data format');
|
|
1524
|
+
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1466
1527
|
this.height = height;
|
|
1467
1528
|
this.width = width;
|
|
1468
1529
|
this.itemSize = itemSize;
|
|
@@ -9,6 +9,7 @@ import { Transform } from '../../ecs/transform/Transform.js';
|
|
|
9
9
|
import { browserInfo } from "../../Platform.js";
|
|
10
10
|
import Vector3 from "../../../core/geom/Vector3.js";
|
|
11
11
|
import { noop } from "../../../core/function/Functions.js";
|
|
12
|
+
import { assert } from "../../../core/assert.js";
|
|
12
13
|
|
|
13
14
|
const v3 = new Vector3();
|
|
14
15
|
const v3_up = new Vector3();
|
|
@@ -86,6 +87,10 @@ class SoundListenerSystem extends System {
|
|
|
86
87
|
*/
|
|
87
88
|
constructor(context) {
|
|
88
89
|
super();
|
|
90
|
+
|
|
91
|
+
assert.defined(context, 'context');
|
|
92
|
+
assert.isInstanceOf(context, AudioContext, 'context', 'AudioContext');
|
|
93
|
+
|
|
89
94
|
this.dependencies = [SoundListener, Transform];
|
|
90
95
|
//
|
|
91
96
|
this.webAudioContext = context;
|