@woosh/meep-engine 2.39.42 → 2.40.0
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/BinaryBuffer.js +8 -0
- package/core/bvh2/aabb3/AABB3.js +0 -133
- package/core/bvh2/aabb3/aabb3_intersects_line_segment.js +1 -1
- package/core/geom/3d/matrix/MATRIX_4_IDENTITY.js +9 -0
- package/core/parser/simple/DataType.js +2 -2
- package/editor/tools/v2/BlenderCameraOrientationGizmo.js +35 -0
- package/editor/view/EditorView.js +25 -22
- package/editor/view/ecs/components/common/NumberController.js +37 -8
- package/engine/EngineHarness.js +0 -3
- package/engine/asset/loaders/image/png/PNGReader.js +41 -2
- package/engine/asset/loaders/image/png/crc.js +66 -0
- package/engine/ecs/speaker/VoiceSystem.js +1 -1
- package/engine/ecs/terrain/ecs/Terrain.js +58 -36
- package/engine/ecs/terrain/ecs/TerrainSystem.js +22 -4
- package/engine/ecs/terrain/tiles/TerrainTile.js +107 -131
- package/engine/ecs/terrain/tiles/TerrainTileManager.js +100 -121
- package/engine/graphics/ecs/camera/Camera.js +1 -1
- package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +4 -4
- package/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +0 -78
- package/engine/graphics/geometry/optimization/merge/merge_geometry_hierarchy.js +0 -9
- package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +2 -2
- package/engine/intelligence/behavior/util/LogMessageBehavior.js +29 -0
- package/package.json +1 -1
|
@@ -85,6 +85,14 @@ export class BinaryBuffer {
|
|
|
85
85
|
this.__growFactor = 1.1;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Access raw underlying bytes attached to the buffer
|
|
90
|
+
* @return {Uint8Array}
|
|
91
|
+
*/
|
|
92
|
+
get raw_bytes() {
|
|
93
|
+
return this.__data_uint8;
|
|
94
|
+
}
|
|
95
|
+
|
|
88
96
|
/**
|
|
89
97
|
* @param {ArrayBuffer} arrayBuffer
|
|
90
98
|
*/
|
package/core/bvh2/aabb3/AABB3.js
CHANGED
|
@@ -551,139 +551,6 @@ export class AABB3 {
|
|
|
551
551
|
return aabb3_intersects_line_segment(this.x0, this.y0, this.z0, this.x1, this.y1, this.z1, startX, startY, startZ, endX, endY, endZ);
|
|
552
552
|
}
|
|
553
553
|
|
|
554
|
-
/**
|
|
555
|
-
* @source http://stackoverflow.com/questions/3106666/intersection-of-line-segment-with-axis-aligned-box-in-c-sharp
|
|
556
|
-
* @param {number} startX
|
|
557
|
-
* @param {number} startY
|
|
558
|
-
* @param {number} startZ
|
|
559
|
-
* @param {number} endX
|
|
560
|
-
* @param {number} endY
|
|
561
|
-
* @param {number} endZ
|
|
562
|
-
* @returns {boolean}
|
|
563
|
-
*/
|
|
564
|
-
intersectSegment2(startX, startY, startZ, endX, endY, endZ) {
|
|
565
|
-
//var beginToEnd = segmentEnd - segmentBegin;
|
|
566
|
-
const deltaX = endX - startX,
|
|
567
|
-
deltaY = endY - startY,
|
|
568
|
-
deltaZ = endZ - startZ;
|
|
569
|
-
//var minToMax = new Vector3D(boxSize.X, boxSize.Y, boxSize.Z);
|
|
570
|
-
|
|
571
|
-
//var min = boxCenter - minToMax / 2;
|
|
572
|
-
//var max = boxCenter + minToMax / 2;
|
|
573
|
-
//var beginToMin = min - segmentBegin;
|
|
574
|
-
//var beginToMax = max - segmentBegin;
|
|
575
|
-
//var tNear = double.MinValue;
|
|
576
|
-
let tNear = Number.NEGATIVE_INFINITY;
|
|
577
|
-
//var tFar = double.MaxValue;
|
|
578
|
-
let tFar = Number.POSITIVE_INFINITY;
|
|
579
|
-
let t1, t2, tMin, tMax;
|
|
580
|
-
//var intersections = new List<Point3D>();
|
|
581
|
-
//var intersections = [];
|
|
582
|
-
let beginToMin = this.x0 - startX;
|
|
583
|
-
let beginToMax = this.x1 - startX;
|
|
584
|
-
if (deltaX === 0) {//parallel
|
|
585
|
-
if (beginToMin > 0 || beginToMax < 0) {
|
|
586
|
-
return false; //segment is not between planes
|
|
587
|
-
}
|
|
588
|
-
} else {
|
|
589
|
-
t1 = beginToMin / deltaX;
|
|
590
|
-
t2 = beginToMax / deltaX;
|
|
591
|
-
tMin = Math.min(t1, t2);
|
|
592
|
-
tMax = Math.max(t1, t2);
|
|
593
|
-
if (tMin > tNear) {
|
|
594
|
-
tNear = tMin;
|
|
595
|
-
}
|
|
596
|
-
if (tMax < tFar) {
|
|
597
|
-
tFar = tMax;
|
|
598
|
-
}
|
|
599
|
-
if (tNear > tFar || tFar < 0) {
|
|
600
|
-
return false;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
beginToMin = this.y0 - startY;
|
|
604
|
-
beginToMax = this.y1 - startY;
|
|
605
|
-
if (deltaY === 0) {//parallel
|
|
606
|
-
if (beginToMin > 0 || beginToMax < 0) {
|
|
607
|
-
return false; //segment is not between planes
|
|
608
|
-
}
|
|
609
|
-
} else {
|
|
610
|
-
t1 = beginToMin / deltaY;
|
|
611
|
-
t2 = beginToMax / deltaY;
|
|
612
|
-
tMin = Math.min(t1, t2);
|
|
613
|
-
tMax = Math.max(t1, t2);
|
|
614
|
-
if (tMin > tNear) {
|
|
615
|
-
tNear = tMin;
|
|
616
|
-
}
|
|
617
|
-
if (tMax < tFar) {
|
|
618
|
-
tFar = tMax;
|
|
619
|
-
}
|
|
620
|
-
if (tNear > tFar || tFar < 0) {
|
|
621
|
-
return false;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
beginToMin = this.z0 - startZ;
|
|
625
|
-
beginToMax = this.z1 - startZ;
|
|
626
|
-
if (deltaZ === 0) {//parallel
|
|
627
|
-
if (beginToMin > 0 || beginToMax < 0) {
|
|
628
|
-
return false; //segment is not between planes
|
|
629
|
-
}
|
|
630
|
-
} else {
|
|
631
|
-
t1 = beginToMin / deltaZ;
|
|
632
|
-
t2 = beginToMax / deltaZ;
|
|
633
|
-
tMin = Math.min(t1, t2);
|
|
634
|
-
tMax = Math.max(t1, t2);
|
|
635
|
-
if (tMin > tNear) {
|
|
636
|
-
tNear = tMin;
|
|
637
|
-
}
|
|
638
|
-
if (tMax < tFar) {
|
|
639
|
-
tFar = tMax;
|
|
640
|
-
}
|
|
641
|
-
if (tNear > tFar || tFar < 0) {
|
|
642
|
-
return false;
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
//
|
|
646
|
-
if (tNear >= 0 && tNear <= 1) {
|
|
647
|
-
//intersections.push({
|
|
648
|
-
// x: startX + deltaX * tNear,
|
|
649
|
-
// y: startY + deltaY * tNear,
|
|
650
|
-
// z: startZ + deltaZ * tNear
|
|
651
|
-
//});
|
|
652
|
-
return true;
|
|
653
|
-
}
|
|
654
|
-
if (tFar >= 0 && tFar <= 1) {
|
|
655
|
-
//intersections.push({
|
|
656
|
-
// x: startX + deltaX * tFar,
|
|
657
|
-
// y: startY + deltaY * tFar,
|
|
658
|
-
// z: startZ + deltaZ * tFar
|
|
659
|
-
//});
|
|
660
|
-
return true;
|
|
661
|
-
}
|
|
662
|
-
return false;
|
|
663
|
-
//foreach (Axis axis in Enum.GetValues(typeof(Axis)))
|
|
664
|
-
//{
|
|
665
|
-
// if (beginToEnd.GetCoordinate(axis) == 0) // parallel
|
|
666
|
-
// {
|
|
667
|
-
// if (beginToMin.GetCoordinate(axis) > 0 || beginToMax.GetCoordinate(axis) < 0)
|
|
668
|
-
// return intersections; // segment is not between planes
|
|
669
|
-
// }
|
|
670
|
-
// else
|
|
671
|
-
// {
|
|
672
|
-
// var t1 = beginToMin.GetCoordinate(axis) / beginToEnd.GetCoordinate(axis);
|
|
673
|
-
// var t2 = beginToMax.GetCoordinate(axis) / beginToEnd.GetCoordinate(axis);
|
|
674
|
-
// var tMin = Math.Min(t1, t2);
|
|
675
|
-
// var tMax = Math.Max(t1, t2);
|
|
676
|
-
// if (tMin > tNear) tNear = tMin;
|
|
677
|
-
// if (tMax < tFar) tFar = tMax;
|
|
678
|
-
// if (tNear > tFar || tFar < 0) return intersections;
|
|
679
|
-
//
|
|
680
|
-
// }
|
|
681
|
-
//}
|
|
682
|
-
//if (tNear >= 0 && tNear <= 1) intersections.Add(segmentBegin + beginToEnd * tNear);
|
|
683
|
-
//if (tFar >= 0 && tFar <= 1) intersections.Add(segmentBegin + beginToEnd * tFar);
|
|
684
|
-
//return intersections;
|
|
685
|
-
}
|
|
686
|
-
|
|
687
554
|
/**
|
|
688
555
|
*
|
|
689
556
|
* @param {THREE.Box} box
|
|
@@ -234,6 +234,13 @@ export class BlenderCameraOrientationGizmo extends CanvasView {
|
|
|
234
234
|
* @type {Signal<string,Vector3>}
|
|
235
235
|
*/
|
|
236
236
|
this.on.axisSelected = new Signal();
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
*
|
|
240
|
+
* @type {boolean}
|
|
241
|
+
* @private
|
|
242
|
+
*/
|
|
243
|
+
this.__needs_update = true;
|
|
237
244
|
}
|
|
238
245
|
|
|
239
246
|
link() {
|
|
@@ -262,6 +269,7 @@ export class BlenderCameraOrientationGizmo extends CanvasView {
|
|
|
262
269
|
*/
|
|
263
270
|
onMouseMove(evt) {
|
|
264
271
|
this._setPointerPositionFromEvent(evt);
|
|
272
|
+
this.__try_update();
|
|
265
273
|
}
|
|
266
274
|
|
|
267
275
|
/**
|
|
@@ -271,9 +279,19 @@ export class BlenderCameraOrientationGizmo extends CanvasView {
|
|
|
271
279
|
*/
|
|
272
280
|
_setPointerPositionFromEvent(evt) {
|
|
273
281
|
const v2 = new Vector2();
|
|
282
|
+
|
|
274
283
|
readPositionFromMouseEvent(v2, evt);
|
|
275
284
|
|
|
285
|
+
const position_changed = (this.input_pointer_position === null || this.input_pointer_position.x !== v2.x || this.input_pointer_position.y !== v2.y);
|
|
286
|
+
|
|
276
287
|
this.input_pointer_position = new Vector3(v2.x, v2.y, 0);
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
if (position_changed) {
|
|
291
|
+
this.__needs_update = true;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
return position_changed;
|
|
277
295
|
}
|
|
278
296
|
|
|
279
297
|
/**
|
|
@@ -282,6 +300,8 @@ export class BlenderCameraOrientationGizmo extends CanvasView {
|
|
|
282
300
|
*/
|
|
283
301
|
onMouseOut(evt) {
|
|
284
302
|
this.input_pointer_position = null;
|
|
303
|
+
this.__needs_update = true;
|
|
304
|
+
this.__try_update();
|
|
285
305
|
}
|
|
286
306
|
|
|
287
307
|
/**
|
|
@@ -289,6 +309,11 @@ export class BlenderCameraOrientationGizmo extends CanvasView {
|
|
|
289
309
|
* @param {MouseEvent} evt
|
|
290
310
|
*/
|
|
291
311
|
onMouseClick(evt) {
|
|
312
|
+
|
|
313
|
+
this._setPointerPositionFromEvent(evt);
|
|
314
|
+
|
|
315
|
+
this.__try_update();
|
|
316
|
+
|
|
292
317
|
if (this.selectedAxis !== null) {
|
|
293
318
|
this.on.axisSelected.send2(
|
|
294
319
|
this.selectedAxis.axis,
|
|
@@ -326,7 +351,17 @@ export class BlenderCameraOrientationGizmo extends CanvasView {
|
|
|
326
351
|
ctx.closePath();
|
|
327
352
|
}
|
|
328
353
|
|
|
354
|
+
__try_update() {
|
|
355
|
+
if (!this.__needs_update) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
this.update();
|
|
359
|
+
}
|
|
360
|
+
|
|
329
361
|
update() {
|
|
362
|
+
// reset flag
|
|
363
|
+
this.__needs_update = false;
|
|
364
|
+
|
|
330
365
|
this.clear();
|
|
331
366
|
|
|
332
367
|
// Calculate the rotation matrix from the camera
|
|
@@ -28,10 +28,11 @@ import SelectionClearAction from "../actions/concrete/SelectionClearAction.js";
|
|
|
28
28
|
import EntityCreateAction from "../actions/concrete/EntityCreateAction.js";
|
|
29
29
|
import ComponentAddAction from "../actions/concrete/ComponentAddAction.js";
|
|
30
30
|
import SelectionAddAction from "../actions/concrete/SelectionAddAction.js";
|
|
31
|
-
import {
|
|
31
|
+
import { passThrough } from "../../core/function/Functions.js";
|
|
32
32
|
import { ProcessState } from "../../core/process/ProcessState.js";
|
|
33
33
|
import { MeshEvents } from "../../engine/graphics/ecs/mesh/MeshEvents.js";
|
|
34
34
|
import { obtainTerrain } from "../../engine/ecs/terrain/util/obtainTerrain.js";
|
|
35
|
+
import { SurfacePoint3 } from "../../core/geom/3d/SurfacePoint3.js";
|
|
35
36
|
|
|
36
37
|
class ViewManager extends View {
|
|
37
38
|
constructor() {
|
|
@@ -204,35 +205,37 @@ function prepareMeshLibrary(editor) {
|
|
|
204
205
|
const entityCreateAction = new EntityCreateAction();
|
|
205
206
|
actions.do(entityCreateAction);
|
|
206
207
|
|
|
207
|
-
|
|
208
|
-
function handleMeshSetEvent() {
|
|
209
|
-
const bb = mesh.boundingBox;
|
|
208
|
+
const sp3 = new SurfacePoint3();
|
|
210
209
|
|
|
211
|
-
|
|
212
|
-
const c1 = new Vector3(bb.x1, bb.y1, bb.z1);
|
|
210
|
+
const hit_found = terrain.raycastFirstSync(sp3, source.x, source.y, source.z, direction.x, direction.y, direction.z);
|
|
213
211
|
|
|
214
|
-
|
|
212
|
+
function handleMeshSetEvent() {
|
|
213
|
+
const bb = mesh.boundingBox;
|
|
215
214
|
|
|
216
|
-
|
|
215
|
+
const c0 = new Vector3(bb.x0, bb.y0, bb.z0);
|
|
216
|
+
const c1 = new Vector3(bb.x1, bb.y1, bb.z1);
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
const diagonal = c0.distanceTo(c1);
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
ecd.removeEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
|
|
222
|
-
}
|
|
220
|
+
const offset = direction.clone().multiplyScalar(diagonal);
|
|
223
221
|
|
|
224
|
-
|
|
225
|
-
//got a terrain ray hit, set world placement position to that point
|
|
226
|
-
worldPosition.copy(hit);
|
|
227
|
-
} else {
|
|
228
|
-
//set position to the source of the ray pick if there's nothing else available
|
|
229
|
-
worldPosition.copy(source);
|
|
222
|
+
transform.position.add(offset);
|
|
230
223
|
|
|
224
|
+
//remove listener
|
|
225
|
+
ecd.removeEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
|
|
226
|
+
}
|
|
231
227
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
228
|
+
if (hit_found) {
|
|
229
|
+
//got a terrain ray hit, set world placement position to that point
|
|
230
|
+
worldPosition.copy(sp3.position);
|
|
231
|
+
} else {
|
|
232
|
+
//set position to the source of the ray pick if there's nothing else available
|
|
233
|
+
worldPosition.copy(source);
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
//wait for mesh to load
|
|
237
|
+
ecd.addEntityEventListener(entityCreateAction.entity, MeshEvents.DataSet, handleMeshSetEvent);
|
|
238
|
+
}
|
|
236
239
|
|
|
237
240
|
transform.position.copy(worldPosition);
|
|
238
241
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import View from "../../../../../view/View.js";
|
|
2
2
|
import Vector1 from "../../../../../core/geom/Vector1.js";
|
|
3
3
|
|
|
4
|
+
const DEFAULT_VALUE = 0;
|
|
5
|
+
|
|
4
6
|
export class NumberController extends View {
|
|
5
7
|
/**
|
|
6
8
|
*
|
|
@@ -32,6 +34,22 @@ export class NumberController extends View {
|
|
|
32
34
|
|
|
33
35
|
let lockForward = false;
|
|
34
36
|
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param {number} num_value
|
|
40
|
+
* @return {string}
|
|
41
|
+
*/
|
|
42
|
+
function format_value_string(num_value) {
|
|
43
|
+
|
|
44
|
+
let str = String(num_value);
|
|
45
|
+
|
|
46
|
+
if (Math.abs(num_value) > 0 && Math.abs(num_value % 1).toString().length > (figures + 2)) {
|
|
47
|
+
str = num_value.toFixed(figures);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return str;
|
|
51
|
+
}
|
|
52
|
+
|
|
35
53
|
function data2view() {
|
|
36
54
|
|
|
37
55
|
if (lockForward) {
|
|
@@ -40,26 +58,37 @@ export class NumberController extends View {
|
|
|
40
58
|
|
|
41
59
|
const num_value = _value.getValue();
|
|
42
60
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
if (Math.abs(num_value) > 0 && Math.abs(num_value % 1).toString().length > (figures + 2)) {
|
|
46
|
-
str = num_value.toFixed(figures);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
el.value = str;
|
|
61
|
+
el.value = format_value_string(num_value);
|
|
50
62
|
|
|
51
63
|
}
|
|
52
64
|
|
|
53
65
|
function view2data() {
|
|
54
66
|
lockForward = true;
|
|
55
67
|
|
|
56
|
-
|
|
68
|
+
const value = parseFloat(el.value);
|
|
69
|
+
|
|
70
|
+
if (Number.isNaN(value)) {
|
|
71
|
+
_value.set(DEFAULT_VALUE);
|
|
72
|
+
} else {
|
|
73
|
+
_value.set(value);
|
|
74
|
+
}
|
|
57
75
|
|
|
58
76
|
lockForward = false;
|
|
59
77
|
}
|
|
60
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Input field stops being edited
|
|
81
|
+
*/
|
|
82
|
+
function handle_blur() {
|
|
83
|
+
if (Number.isNaN(parseFloat(el.value))) {
|
|
84
|
+
// input in the field is invalid, replace with the value held in the data container
|
|
85
|
+
el.value = format_value_string(_value.getValue());
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
61
89
|
_value.process(data2view);
|
|
62
90
|
|
|
63
91
|
el.addEventListener('input', view2data);
|
|
92
|
+
el.addEventListener('blur', handle_blur);
|
|
64
93
|
}
|
|
65
94
|
}
|
package/engine/EngineHarness.js
CHANGED
|
@@ -9,7 +9,6 @@ import Vector3 from "../core/geom/Vector3.js";
|
|
|
9
9
|
import Terrain from "./ecs/terrain/ecs/Terrain.js";
|
|
10
10
|
import Vector2 from "../core/geom/Vector2.js";
|
|
11
11
|
import Water from "./graphics/ecs/water/Water.js";
|
|
12
|
-
import { loadGameClassRegistry } from "../../model/game/GameClassRegistry.js";
|
|
13
12
|
import { WebEnginePlatform } from "./platform/WebEnginePlatform.js";
|
|
14
13
|
import Tag from "./ecs/components/Tag.js";
|
|
15
14
|
import { SerializationMetadata } from "./ecs/components/SerializationMetadata.js";
|
|
@@ -116,8 +115,6 @@ export class EngineHarness {
|
|
|
116
115
|
|
|
117
116
|
await setLocale(engine);
|
|
118
117
|
|
|
119
|
-
loadGameClassRegistry(engine.classRegistry);
|
|
120
|
-
|
|
121
118
|
engine.sceneManager.create("test");
|
|
122
119
|
engine.sceneManager.set("test");
|
|
123
120
|
|
|
@@ -7,7 +7,14 @@ import { PNG } from './PNG.js';
|
|
|
7
7
|
import { BinaryBuffer } from "../../../../../core/binary/BinaryBuffer.js";
|
|
8
8
|
import { isArrayEqualStrict } from "../../../../../core/collection/array/isArrayEqualStrict.js";
|
|
9
9
|
import { PNG_HEADER_BYTES } from "./PNG_HEADER_BYTES.js";
|
|
10
|
+
import { crc } from "./crc.js";
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {Uint8Array} buffer
|
|
15
|
+
* @param {number} offset
|
|
16
|
+
* @return {number}
|
|
17
|
+
*/
|
|
11
18
|
function readUInt32(buffer, offset) {
|
|
12
19
|
return (buffer[offset] << 24) +
|
|
13
20
|
(buffer[offset + 1] << 16) +
|
|
@@ -16,6 +23,12 @@ function readUInt32(buffer, offset) {
|
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @param {Uint8Array} buffer
|
|
29
|
+
* @param {number} offset
|
|
30
|
+
* @return {number}
|
|
31
|
+
*/
|
|
19
32
|
function readUInt8(buffer, offset) {
|
|
20
33
|
return buffer[offset];
|
|
21
34
|
}
|
|
@@ -37,8 +50,19 @@ export function PNGReader(bytes) {
|
|
|
37
50
|
|
|
38
51
|
this.buffer = new BinaryBuffer();
|
|
39
52
|
this.buffer.fromArrayBuffer(bytes);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Whether CRC should be performed or not
|
|
56
|
+
* @type {boolean}
|
|
57
|
+
*/
|
|
58
|
+
this.crc_enabled = false;
|
|
40
59
|
}
|
|
41
60
|
|
|
61
|
+
/**
|
|
62
|
+
*
|
|
63
|
+
* @param {number} length
|
|
64
|
+
* @return {Uint8Array}
|
|
65
|
+
*/
|
|
42
66
|
PNGReader.prototype.readBytes = function (length) {
|
|
43
67
|
const result = new Uint8Array(length);
|
|
44
68
|
|
|
@@ -91,16 +115,31 @@ PNGReader.prototype.decodeChunk = function () {
|
|
|
91
115
|
throw new Error('Bad chunk length ' + (0xFFFFFFFF & length));
|
|
92
116
|
}
|
|
93
117
|
|
|
118
|
+
|
|
119
|
+
const chunk_address = buffer.position;
|
|
120
|
+
|
|
94
121
|
const type = buffer.readASCIICharacters(4);
|
|
95
122
|
|
|
96
123
|
/**
|
|
97
124
|
*
|
|
98
125
|
* @type {Uint8Array}
|
|
99
126
|
*/
|
|
100
|
-
|
|
127
|
+
const chunk = this.readBytes(length);
|
|
101
128
|
|
|
102
129
|
// checksum
|
|
103
|
-
|
|
130
|
+
const crc_expected = buffer.readUint32();
|
|
131
|
+
|
|
132
|
+
if (this.crc_enabled) {
|
|
133
|
+
|
|
134
|
+
// NOTE: CRC includes the "type" tag, not just the chunk bytes
|
|
135
|
+
const crc_actual = crc(buffer.raw_bytes, chunk_address, length + 4);
|
|
136
|
+
|
|
137
|
+
if (crc_actual !== crc_expected) {
|
|
138
|
+
console.warn(`CRC (Cyclic Redundancy Check) error at block '${type}' at address ${chunk_address}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
}
|
|
142
|
+
|
|
104
143
|
|
|
105
144
|
switch (type) {
|
|
106
145
|
case 'IHDR':
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Ported from C source at https://www.w3.org/TR/PNG-CRCAppendix.html
|
|
3
|
+
* See also ISO 3309 [ISO-3309] or ITU-T V.42 [ITU-V42] for a formal specification
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @type {Uint32Array}
|
|
9
|
+
*/
|
|
10
|
+
const crc_table = new Uint32Array(256);
|
|
11
|
+
|
|
12
|
+
// Precompute checksum table
|
|
13
|
+
for (let n = 0; n < 256; n++) {
|
|
14
|
+
let c = n;
|
|
15
|
+
for (let k = 0; k < 8; k++) {
|
|
16
|
+
if (c & 1) {
|
|
17
|
+
c = 0xedb88320 ^ (c >>> 1);
|
|
18
|
+
} else {
|
|
19
|
+
c = c >>> 1;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
crc_table[n] = c;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const INITIAL = 0xffffffff;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Update a running CRC with the bytes buf[0..len-1]--the CRC
|
|
29
|
+
* should be initialized to all 1's, and the transmitted value
|
|
30
|
+
* is the 1's complement of the final running CRC (see the
|
|
31
|
+
* crc() routine below)).
|
|
32
|
+
* @param {number} crc
|
|
33
|
+
* @param {Uint8Array} buf
|
|
34
|
+
* @param {number} offset
|
|
35
|
+
* @param {number} len
|
|
36
|
+
* @return {number}
|
|
37
|
+
*/
|
|
38
|
+
function update_crc(
|
|
39
|
+
crc,
|
|
40
|
+
buf,
|
|
41
|
+
offset,
|
|
42
|
+
len,
|
|
43
|
+
) {
|
|
44
|
+
let c = crc;
|
|
45
|
+
|
|
46
|
+
const end = offset + len;
|
|
47
|
+
|
|
48
|
+
for (let n = offset; n < end; n++) {
|
|
49
|
+
const lookup_index = (c ^ buf[n]) & 0xff;
|
|
50
|
+
|
|
51
|
+
c = crc_table[lookup_index] ^ (c >>> 8);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return c;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns CRC of the bytes buf[0..len-1]
|
|
59
|
+
* @param {Uint8Array} buf byte buffer
|
|
60
|
+
* @param {number} offset
|
|
61
|
+
* @param {number} len how many bytes to include in checksum calculation
|
|
62
|
+
* @return {number}
|
|
63
|
+
*/
|
|
64
|
+
export function crc(buf, offset, len) {
|
|
65
|
+
return (update_crc(INITIAL, buf, offset, len) ^ INITIAL) >>> 0;
|
|
66
|
+
}
|
|
@@ -429,7 +429,7 @@ export class VoiceSystem extends AbstractContextSystem {
|
|
|
429
429
|
const bb = ecd.getComponent(entity, Blackboard);
|
|
430
430
|
|
|
431
431
|
if (bb !== undefined) {
|
|
432
|
-
bb.
|
|
432
|
+
bb.incrementNumber(`voice.line_spoken.${line_id}.count`);
|
|
433
433
|
}
|
|
434
434
|
|
|
435
435
|
}
|