@woosh/meep-engine 2.43.51 → 2.43.53

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.
@@ -0,0 +1,17 @@
1
+ /**
2
+ *
3
+ * @param {Uint8Array|Uint16Array|Uint32Array|Int8Array|Int16Array|Int32Array} array
4
+ * @return {boolean}
5
+ */
6
+ export function typed_array_is_integer(array) {
7
+ const ctor = array.constructor;
8
+
9
+ return ctor === Uint8ClampedArray
10
+ || ctor === Uint8Array
11
+ || ctor === Uint16Array
12
+ || ctor === Uint32Array
13
+ || ctor === Int8Array
14
+ || ctor === Int16Array
15
+ || ctor === Int32Array
16
+ ;
17
+ }
@@ -24,7 +24,9 @@ export class Transform {
24
24
 
25
25
  clone(): Transform
26
26
 
27
- equals(other: Transform): void
27
+ equals(other: Transform): boolean
28
+
29
+ hash(): number
28
30
 
29
31
  toMatrix4(result: ArrayLike<number>): void
30
32
 
@@ -32,5 +34,5 @@ export class Transform {
32
34
 
33
35
  multiplyTransforms(a: Transform, b: Transform): void
34
36
 
35
- makeIdentity():void
37
+ makeIdentity(): void
36
38
  }
@@ -10,7 +10,7 @@ import { Sampler2D } from "../../../texture/sampler/Sampler2D.js";
10
10
  import { GameAssetType } from "../../../../asset/GameAssetType.js";
11
11
  import { assert } from "../../../../../core/assert.js";
12
12
  import { AsyncLoadingCache } from "../../../../../core/collection/map/AsyncLoadingCache.js";
13
- import { copy_Sampler2D_channel_data } from "../../../texture/sampler/copy_Sampler2D_channel_data.js";
13
+ import { sampler2d_to_uint8_RGBA } from "../../../texture/sampler/sampler2d_to_uint8_RGBA.js";
14
14
 
15
15
  const placeholder_texture = Sampler2D.uint8(4, 1, 1);
16
16
  placeholder_texture.data.fill(255);
@@ -108,6 +108,13 @@ class Context extends SystemEntityContext {
108
108
  */
109
109
  const decal_spec = this.components[0];
110
110
 
111
+ // propagate draw priority onto decal
112
+ Object.defineProperty(fpDecal, 'draw_priority', {
113
+ get() {
114
+ return decal_spec.priority;
115
+ }
116
+ });
117
+
111
118
  this.__load_texture().then(() => {
112
119
 
113
120
  if (!this.__is_linked) {
@@ -177,7 +184,7 @@ export class FPDecalSystem extends AbstractContextSystem {
177
184
 
178
185
  const resampled = Sampler2D.uint8(4, asset_sampler.width, asset_sampler.height);
179
186
 
180
- copy_Sampler2D_channel_data(asset_sampler, resampled);
187
+ sampler2d_to_uint8_RGBA(resampled, asset_sampler);
181
188
 
182
189
  return resampled;
183
190
  });
@@ -300,7 +300,7 @@ function makeNormalTestGridDecal(ecd, root_transform = new Transform()) {
300
300
  SPACING * j,
301
301
  0,
302
302
  );
303
- transform.scale.setScalar(1);
303
+ transform.scale.setScalar(3);
304
304
  transform.rotation._lookRotation(direction[0],direction[2], direction[1] , 0, 1, 0);
305
305
 
306
306
  transform.multiplyTransforms(root_transform, transform);
@@ -312,6 +312,10 @@ function makeNormalTestGridDecal(ecd, root_transform = new Transform()) {
312
312
  .add(decal)
313
313
  .build(ecd);
314
314
 
315
+ setInterval(()=>{
316
+ decal.priority = Math.random();
317
+ },7000);
318
+
315
319
 
316
320
  // make an arrow helper
317
321
  const arrow_transform = Transform.fromJSON({
@@ -503,6 +503,13 @@ export class LightManager {
503
503
  if (light instanceof Decal) {
504
504
  const ref = this.__decal_references.get(light);
505
505
 
506
+ if (ref === undefined) {
507
+ // This can occur when decal changes while being in the visible list, messing with the IncrementalDeltaSet's compare order
508
+ console.warn(`Decal reference not found: ${light}, likely live decal changed`);
509
+ // TODO address this case properly
510
+ return;
511
+ }
512
+
506
513
  const patch = ref.getValue();
507
514
  const patch_uv = patch.uv;
508
515
 
@@ -5,6 +5,10 @@ export class AbstractLight {
5
5
  this.id = id_counter++;
6
6
  }
7
7
 
8
+ toString() {
9
+ return `Light#${this.id}`;
10
+ }
11
+
8
12
  /**
9
13
  *
10
14
  * @param {function} f
@@ -3,6 +3,9 @@
3
3
  */
4
4
 
5
5
 
6
+ import { Sampler2D } from "./Sampler2D.js";
7
+ import { sample2d_write_to_canvas_raw } from "./sample2d_write_to_canvas_raw.js";
8
+
6
9
  /**
7
10
  *
8
11
  * @param {Sampler2D} sampler
@@ -12,32 +15,20 @@
12
15
  * @param {function(index:int, array:ArrayLike<number>, x:int, y:int)} [fillDD] allows you to supply mapping function, if none is given - one will be created from sampler using {@link Sampler2D#makeArrayFiller}
13
16
  * @returns {HTMLCanvasElement} canvas
14
17
  */
15
- function convertSampler2D2Canvas(sampler, scale=255, offset=0, canvas, fillDD) {
18
+ function convertSampler2D2Canvas(sampler, scale = 255, offset = 0, canvas, fillDD) {
16
19
  const source_data = sampler.data;
17
20
 
18
21
  //generate canvas
19
22
  if (canvas === undefined) {
20
23
  canvas = document.createElement("canvas");
21
24
  }
22
- const width = sampler.width;
23
- const height = sampler.height;
24
-
25
- if (canvas.width !== width) {
26
- canvas.width = width;
27
- }
28
25
 
29
- if (canvas.height !== height) {
30
- canvas.height = height;
31
- }
26
+ const converted_sampler = Sampler2D.uint8(4, sampler.width, sampler.height);
32
27
 
33
- if (height === 0 || width === 0) {
34
- //there is no data, just return canvas
35
- return canvas;
36
- }
28
+ const width = sampler.width;
29
+ const height = sampler.height;
37
30
 
38
- const context = canvas.getContext("2d");
39
- const imageData = context.createImageData(width, height);
40
- const array = imageData.data;
31
+ const array = converted_sampler.data;
41
32
  //
42
33
  const source_channel_count = sampler.itemSize;
43
34
  if (source_channel_count === 4 && offset === 0 && scale === 1) {
@@ -94,7 +85,8 @@ function convertSampler2D2Canvas(sampler, scale=255, offset=0, canvas, fillDD) {
94
85
 
95
86
  }
96
87
 
97
- context.putImageData(imageData, 0, 0);
88
+ sample2d_write_to_canvas_raw(converted_sampler, canvas);
89
+
98
90
  return canvas;
99
91
  }
100
92
 
@@ -1,3 +1,5 @@
1
+ import { saturated_value_by_constructor } from "./saturated_value_by_constructor.js";
2
+
1
3
  /**
2
4
  * Allows copying data from one sampler to another with unequal number of channels (a.itemSize !== b.itemSize)
3
5
  * @example convert RGBA to RGB or R to RGB
@@ -19,12 +21,14 @@ export function copy_Sampler2D_channel_data(source, destination) {
19
21
 
20
22
  let i, j;
21
23
 
24
+ const saturated_channel_value = saturated_value_by_constructor(destination_data.constructor);
25
+
22
26
  if (source_item_size === destination_item_size) {
23
27
  // just copy data chunk
24
28
  destination_data.set(source_data);
25
29
 
26
30
  } else if (source_item_size > destination_item_size) {
27
-
31
+ // more channels in source than in destination
28
32
  for (i = 0; i < pixel_count; i++) {
29
33
  const source_sample_offset = i * source_item_size;
30
34
  const destination_sample_offset = i * destination_item_size;
@@ -44,7 +48,7 @@ export function copy_Sampler2D_channel_data(source, destination) {
44
48
  destination_data[i4 + 1] = source_data[i3 + 1];
45
49
  destination_data[i4 + 2] = source_data[i3 + 2];
46
50
 
47
- destination_data[i4 + 3] = 255; // fill alpha
51
+ destination_data[i4 + 3] = saturated_channel_value; // fill alpha
48
52
  }
49
53
  } else if (source_item_size === 2 && destination_item_size === 4) {
50
54
  //RA -> RGBA
@@ -0,0 +1,38 @@
1
+ import { Sampler2D } from "./Sampler2D.js";
2
+ import { sampler2d_to_uint8_RGBA } from "./sampler2d_to_uint8_RGBA.js";
3
+
4
+ /**
5
+ *
6
+ * @param {Sampler2D} sampler
7
+ * @param {HTMLCanvasElement} canvas
8
+ */
9
+ export function sample2d_write_to_canvas_raw(sampler, canvas) {
10
+
11
+ const width = sampler.width;
12
+ const height = sampler.height;
13
+
14
+ if (canvas.width !== width) {
15
+ canvas.width = width;
16
+ }
17
+
18
+ if (canvas.height !== height) {
19
+ canvas.height = height;
20
+ }
21
+
22
+ if (height === 0 || width === 0) {
23
+ //there is no data, just return
24
+ return;
25
+ }
26
+
27
+ const context = canvas.getContext("2d");
28
+
29
+ const imageData = context.createImageData(width, height);
30
+ const array = imageData.data;
31
+
32
+ const destination_sampler = new Sampler2D(array, 4, width, height);
33
+
34
+ sampler2d_to_uint8_RGBA(destination_sampler, sampler);
35
+
36
+ context.putImageData(imageData, 0, 0);
37
+
38
+ }
@@ -0,0 +1,68 @@
1
+ import { typed_array_is_integer } from "../../../../core/collection/array/typed/typed_array_is_integer.js";
2
+
3
+ /**
4
+ * Applies a linear polynomial transform to each value of a given channel
5
+ * @param {Sampler2D} output
6
+ * @param {Sampler2D} input
7
+ * @param {number} output_channel_index
8
+ * @param {number} input_channel_index
9
+ * @param {number} gradient
10
+ * @param {number} intercept
11
+ */
12
+ export function sampler2d_channel_linear_transform(
13
+ output, input,
14
+ output_channel_index, input_channel_index,
15
+ gradient, intercept
16
+ ) {
17
+
18
+ const input_width = input.width;
19
+ const input_height = input.height;
20
+
21
+ const output_width = output.width;
22
+ const output_height = output.height;
23
+
24
+ if (
25
+ input_width !== output_width
26
+ || input_height !== output_height
27
+ ) {
28
+ throw new Error('Dimensions of input and output are incompatible');
29
+ }
30
+
31
+ const input_item_size = input.itemSize;
32
+ const output_item_size = output.itemSize;
33
+
34
+ const input_data = input.data;
35
+ const output_data = output.data;
36
+
37
+ const pixel_count = input_width * input_height;
38
+
39
+
40
+ if (typed_array_is_integer(output_data)) {
41
+
42
+ for (let i = 0; i < pixel_count; i++) {
43
+
44
+ const input_address = i * input_item_size + input_channel_index;
45
+ const output_address = i * output_item_size + output_channel_index;
46
+
47
+ const input_value = input_data[input_address];
48
+
49
+ output_data[output_address] = Math.round(input_value * gradient + intercept);
50
+
51
+ }
52
+
53
+ } else {
54
+
55
+ for (let i = 0; i < pixel_count; i++) {
56
+
57
+ const input_address = i * input_item_size + input_channel_index;
58
+ const output_address = i * output_item_size + output_channel_index;
59
+
60
+ const input_value = input_data[input_address];
61
+
62
+ output_data[output_address] = input_value * gradient + intercept;
63
+
64
+ }
65
+
66
+ }
67
+
68
+ }
@@ -0,0 +1,97 @@
1
+ import { sampler2d_channel_linear_transform } from "./sampler2d_channel_linear_transform.js";
2
+
3
+ function compute_gradient_and_intercept_uint8(ctor) {
4
+ let gradient = 1;
5
+ let intercept = 0;
6
+
7
+ switch (ctor) {
8
+ case Uint16Array:
9
+ gradient = 0.0038910505836575876;
10
+ break;
11
+ case Uint32Array:
12
+ gradient = 5.937181414556033e-8;
13
+ break;
14
+ case Int8Array:
15
+ gradient = 1;
16
+ intercept = 127;
17
+ break
18
+ case Int16Array:
19
+ gradient = 0.0038910505836575876;
20
+ intercept = 127;
21
+ break;
22
+ case Int32Array:
23
+ gradient = 5.937181414556033e-8;
24
+ intercept = 127;
25
+ break
26
+ case Float32Array:
27
+ case Float64Array:
28
+ gradient = 255;
29
+ break;
30
+ default:
31
+ // do nothing;
32
+ }
33
+
34
+ return {
35
+ gradient, intercept
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Many applications work with 8bit RGBA images, this utility function converts a given input to that format
41
+ * @param {Sampler2D} input
42
+ * @param {Sampler2D} output
43
+ */
44
+ export function sampler2d_to_uint8_RGBA(output, input) {
45
+ if (
46
+ input.width !== output.width
47
+ || input.height !== output.height
48
+ ) {
49
+ throw new Error('Dimensions of source and destination are incompatible');
50
+ }
51
+
52
+ if (output.itemSize !== 4) {
53
+ throw new Error(`Destination must have 4 channels exactly, instead got '${output.itemSize}'`);
54
+ }
55
+
56
+ const { gradient, intercept } = compute_gradient_and_intercept_uint8(input.data.constructor);
57
+
58
+ const source_item_size = input.itemSize;
59
+
60
+ if (intercept === 0 && gradient === 1 && source_item_size === 4) {
61
+ // already in the right format, use shortcut
62
+ output.data.set(input.data);
63
+ return;
64
+ }
65
+
66
+ if (source_item_size === 1) {
67
+
68
+ sampler2d_channel_linear_transform(output, input, 0, 0, gradient, intercept);
69
+ sampler2d_channel_linear_transform(output, input, 1, 0, gradient, intercept);
70
+ sampler2d_channel_linear_transform(output, input, 2, 0, gradient, intercept);
71
+
72
+ output.fill_channel(3, 255);
73
+
74
+ } else if (source_item_size === 2) {
75
+
76
+ sampler2d_channel_linear_transform(output, input, 0, 0, gradient, intercept);
77
+ sampler2d_channel_linear_transform(output, input, 1, 0, gradient, intercept);
78
+ sampler2d_channel_linear_transform(output, input, 2, 0, gradient, intercept);
79
+ sampler2d_channel_linear_transform(output, input, 3, 1, gradient, intercept);
80
+
81
+ } else if (source_item_size === 3) {
82
+
83
+ sampler2d_channel_linear_transform(output, input, 0, 0, gradient, intercept);
84
+ sampler2d_channel_linear_transform(output, input, 1, 1, gradient, intercept);
85
+ sampler2d_channel_linear_transform(output, input, 2, 2, gradient, intercept);
86
+
87
+ output.fill_channel(3, 255);
88
+
89
+ } else if (source_item_size === 4) {
90
+
91
+ sampler2d_channel_linear_transform(output, input, 0, 0, gradient, intercept);
92
+ sampler2d_channel_linear_transform(output, input, 1, 1, gradient, intercept);
93
+ sampler2d_channel_linear_transform(output, input, 2, 2, gradient, intercept);
94
+ sampler2d_channel_linear_transform(output, input, 3, 3, gradient, intercept);
95
+
96
+ }
97
+ }
@@ -0,0 +1,52 @@
1
+ import { sampler2d_to_uint8_RGBA } from "./sampler2d_to_uint8_RGBA.js";
2
+ import { Sampler2D } from "./Sampler2D.js";
3
+
4
+ test('uint8 RGBA input', () => {
5
+
6
+ const source = new Sampler2D(new Uint8Array([1,3,7,11]), 4, 1, 1);
7
+ const destination = Sampler2D.uint8(4, 1, 1);
8
+
9
+ sampler2d_to_uint8_RGBA(destination, source);
10
+
11
+ expect(Array.from(destination.data)).toEqual([1,3,7,11]);
12
+ });
13
+
14
+ test('uint8 RGB input', () => {
15
+
16
+ const source = new Sampler2D(new Uint8Array([1,3,7]), 3, 1, 1);
17
+ const destination = Sampler2D.uint8(4, 1, 1);
18
+
19
+ sampler2d_to_uint8_RGBA(destination, source);
20
+
21
+ expect(Array.from(destination.data)).toEqual([1,3,7,255]);
22
+ });
23
+
24
+ test('uint8 RG input', () => {
25
+
26
+ const source = new Sampler2D(new Uint8Array([1,3]), 2, 1, 1);
27
+ const destination = Sampler2D.uint8(4, 1, 1);
28
+
29
+ sampler2d_to_uint8_RGBA(destination, source);
30
+
31
+ expect(Array.from(destination.data)).toEqual([1,1,1,3]);
32
+ });
33
+
34
+ test('uint8 R input', () => {
35
+
36
+ const source = new Sampler2D(new Uint8Array([1]), 1, 1, 1);
37
+ const destination = Sampler2D.uint8(4, 1, 1);
38
+
39
+ sampler2d_to_uint8_RGBA(destination, source);
40
+
41
+ expect(Array.from(destination.data)).toEqual([1,1,1,255]);
42
+ });
43
+
44
+ test('float32 RGBA input', () => {
45
+
46
+ const source = new Sampler2D(new Float32Array([0.1,0.3,0.7,0.11]), 4, 1, 1);
47
+ const destination = Sampler2D.uint8(4, 1, 1);
48
+
49
+ sampler2d_to_uint8_RGBA(destination, source);
50
+
51
+ expect(Array.from(destination.data)).toEqual([26, 77, 178, 28]);
52
+ });
@@ -0,0 +1,28 @@
1
+ /**
2
+ *
3
+ * @param {*} ctor
4
+ * @returns {number}
5
+ */
6
+ export function saturated_value_by_constructor(ctor) {
7
+
8
+ switch (ctor) {
9
+ case Uint8Array:
10
+ return 255;
11
+ case Uint16Array:
12
+ return 65535;
13
+ case Uint32Array:
14
+ return 4294967295;
15
+ case Int8Array:
16
+ return 127;
17
+ case Int16Array:
18
+ return 32767;
19
+ case Int32Array:
20
+ return 2147483647;
21
+ case Float32Array:
22
+ case Float64Array:
23
+ return 1;
24
+ default:
25
+ return 1;
26
+ }
27
+
28
+ }
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.43.51",
8
+ "version": "2.43.53",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",