@woosh/meep-engine 2.39.11 → 2.39.14
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/geom/3d/topology/bounds/computeTopoMeshBoundingSphere.js +2 -1
- package/editor/ecs/component/createFieldEditor.js +2 -0
- package/editor/ecs/component/editors/Sampler2DEditor.js +163 -49
- package/editor/ecs/component/editors/three/TextureEditor.js +81 -3
- package/engine/ecs/terrain/ecs/Terrain.js +9 -4
- package/engine/ecs/terrain/ecs/TerrainSystem.js +0 -1
- package/engine/ecs/terrain/overlay/TerrainOverlay.js +23 -3
- package/engine/graphics/WHITE_PIXEL_DATA_URL.js +1 -0
- package/engine/graphics/ecs/path/testPathDisplaySystem.js +1 -1
- package/engine/graphics/ecs/path/tube/TubePathStyle.spec.js +5 -0
- package/engine/graphics/micron/build/hierarchy/build_merge_graph.js +1 -0
- package/engine/graphics/micron/build/hierarchy/computePatchMergeScore.js +18 -4
- package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +15 -5
- package/engine/graphics/texture/sampler/Sampler2D2Canvas.js +42 -14
- package/engine/graphics/texture/sampler/convertSampler2D2DataURL.js +7 -1
- package/engine/graphics/texture/sampler/copy_Sampler2D_channel_data.js +3 -0
- package/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.js +47 -0
- package/package.json +1 -1
- package/view/View.js +3 -3
|
@@ -28,9 +28,10 @@ export function computeTopoMeshBoundingSphere(result, mesh) {
|
|
|
28
28
|
const miniball = new Miniball(pointSet);
|
|
29
29
|
|
|
30
30
|
const center = miniball.center();
|
|
31
|
+
const radius = miniball.radius();
|
|
31
32
|
|
|
32
33
|
result[0] = center[0];
|
|
33
34
|
result[1] = center[1];
|
|
34
35
|
result[2] = center[2];
|
|
35
|
-
result[3] =
|
|
36
|
+
result[3] = radius;
|
|
36
37
|
}
|
|
@@ -6,74 +6,169 @@ import { Sampler2D } from "../../../../engine/graphics/texture/sampler/Sampler2D
|
|
|
6
6
|
import {
|
|
7
7
|
typedArrayConstructorByInstance
|
|
8
8
|
} from "../../../../engine/graphics/texture/sampler/typedArrayConstructorByInstance.js";
|
|
9
|
-
import { typedArrayToDataType } from "../../../../core/collection/array/typedArrayToDataType.js";
|
|
10
|
-
import { DataType } from "../../../../core/collection/table/DataType.js";
|
|
11
|
-
import { min2 } from "../../../../core/math/min2.js";
|
|
12
|
-
import { max2 } from "../../../../core/math/max2.js";
|
|
13
|
-
import { isTypedArray } from "../../../../core/collection/array/typed/isTypedArray.js";
|
|
14
9
|
import { FrameRunner } from "../../../../engine/graphics/FrameRunner.js";
|
|
10
|
+
import canvas2Sampler2D from "../../../../engine/graphics/texture/Canvas2Sampler2D.js";
|
|
11
|
+
import {
|
|
12
|
+
copy_Sampler2D_channel_data
|
|
13
|
+
} from "../../../../engine/graphics/texture/sampler/copy_Sampler2D_channel_data.js";
|
|
14
|
+
import { MouseEvents } from "../../../../engine/input/devices/events/MouseEvents.js";
|
|
15
|
+
import { downloadSampler2DAsPNG } from "../../../../engine/graphics/texture/sampler/downloadSamplerAsPNG.js";
|
|
16
|
+
import {
|
|
17
|
+
sampler2d_compute_texel_value_conversion_scale_to_uint8
|
|
18
|
+
} from "../../../../engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.js";
|
|
19
|
+
import EmptyView from "../../../../view/elements/EmptyView.js";
|
|
15
20
|
|
|
16
21
|
const UPDATE_DELAY = 200;
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param {Sampler2D} sampler
|
|
26
|
+
* @param {HTMLCanvasElement} domElement
|
|
27
|
+
*/
|
|
28
|
+
function draw_sampler(sampler, domElement) {
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
let TypedArrayConstructor = typedArrayConstructorByInstance(sampler.data);
|
|
32
|
+
|
|
33
|
+
if (TypedArrayConstructor === Uint8Array) {
|
|
34
|
+
// use clamped array to avoid filtering artifacts
|
|
35
|
+
TypedArrayConstructor = Uint8ClampedArray;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const res = 32;
|
|
39
|
+
const result_sampler = new Sampler2D(new TypedArrayConstructor(sampler.itemSize * res * res), sampler.itemSize, res, res);
|
|
40
|
+
|
|
41
|
+
scaleSampler2D(sampler, result_sampler);
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
const { scale, offset } = sampler2d_compute_texel_value_conversion_scale_to_uint8(result_sampler);
|
|
45
|
+
|
|
46
|
+
sampler2D2Canvas(result_sampler, scale, offset, domElement);
|
|
47
|
+
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
* @param {*} parent
|
|
53
|
+
* @param {HTMLCanvasElement} element
|
|
54
|
+
* @param {FieldDescriptor} field
|
|
55
|
+
*/
|
|
56
|
+
function enable_drop(parent, element, field) {
|
|
57
|
+
/**
|
|
58
|
+
*
|
|
59
|
+
* @param {DragEvent} ev
|
|
60
|
+
*/
|
|
61
|
+
function handleDrop(ev) {
|
|
62
|
+
ev.preventDefault();
|
|
63
|
+
|
|
64
|
+
let processed = false;
|
|
20
65
|
|
|
21
66
|
/**
|
|
22
|
-
*
|
|
67
|
+
*
|
|
68
|
+
* @param {File} file
|
|
23
69
|
*/
|
|
24
|
-
|
|
70
|
+
function processFile(file) {
|
|
71
|
+
if (processed) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
25
74
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
75
|
+
var img = new Image();
|
|
76
|
+
// URL @ Mozilla, webkitURL @ Chrome
|
|
77
|
+
img.src = (window.webkitURL ? webkitURL : URL).createObjectURL(file);
|
|
29
78
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
79
|
+
// call ctx.drawImage when the image got loaded
|
|
80
|
+
img.onload = function () {
|
|
81
|
+
var canvas = document.createElement("canvas");
|
|
82
|
+
var ctx = canvas.getContext("2d");
|
|
34
83
|
|
|
35
|
-
|
|
36
|
-
|
|
84
|
+
const width = img.width;
|
|
85
|
+
const height = img.height;
|
|
37
86
|
|
|
38
|
-
|
|
87
|
+
canvas.style.width = `${width}px`;
|
|
88
|
+
canvas.style.height = `${height}px`;
|
|
39
89
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
} else {
|
|
43
|
-
dataType = DataType.Float32;
|
|
44
|
-
}
|
|
90
|
+
canvas.width = width;
|
|
91
|
+
canvas.height = height;
|
|
45
92
|
|
|
46
|
-
|
|
93
|
+
// ctx.drawImage(img, 0, 0);
|
|
94
|
+
ctx.drawImage(img, 0, 0, width, height, 0, 0, width, height); // stretch img to canvas size
|
|
47
95
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
96
|
+
const file_data_sampler = canvas2Sampler2D(canvas);
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @type {Sampler2D}
|
|
100
|
+
*/
|
|
101
|
+
const sampler = field.adapter.read(parent, field.name);
|
|
102
|
+
|
|
103
|
+
sampler.resize(width, height, false);
|
|
52
104
|
|
|
53
|
-
|
|
54
|
-
|
|
105
|
+
copy_Sampler2D_channel_data(file_data_sampler, sampler);
|
|
106
|
+
};
|
|
55
107
|
|
|
56
|
-
scaleSampler2D(sampler, result_sampler);
|
|
57
108
|
|
|
109
|
+
processed = true;
|
|
110
|
+
}
|
|
58
111
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
112
|
+
if (ev.dataTransfer.items) {
|
|
113
|
+
// Use DataTransferItemList interface to access the file(s)
|
|
114
|
+
for (var i = 0; i < ev.dataTransfer.items.length; i++) {
|
|
115
|
+
// If dropped items aren't files, reject them
|
|
116
|
+
if (ev.dataTransfer.items[i].kind === 'file') {
|
|
117
|
+
var file = ev.dataTransfer.items[i].getAsFile();
|
|
64
118
|
|
|
65
|
-
|
|
66
|
-
max = max2(min, result_sampler.computeMax(i).value)
|
|
119
|
+
processFile(file);
|
|
67
120
|
}
|
|
68
|
-
} else if (dataType === DataType.Uint8) {
|
|
69
|
-
min = 0;
|
|
70
|
-
max = 255;
|
|
71
121
|
}
|
|
122
|
+
} else {
|
|
123
|
+
// Use DataTransfer interface to access the file(s)
|
|
124
|
+
for (var i = 0; i < ev.dataTransfer.files.length; i++) {
|
|
125
|
+
const file = ev.dataTransfer.files[i];
|
|
126
|
+
|
|
127
|
+
processFile(file);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function handleDragOver(ev) {
|
|
133
|
+
|
|
134
|
+
// Prevent default behavior (Prevent file from being opened)
|
|
135
|
+
ev.preventDefault();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
element.addEventListener('dragover', handleDragOver);
|
|
139
|
+
element.addEventListener('drop', handleDrop);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export class Sampler2DEditor extends TypeEditor {
|
|
143
|
+
|
|
144
|
+
build(parent, field, context) {
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @type {Sampler2D}
|
|
148
|
+
*/
|
|
149
|
+
const sampler = field.adapter.read(parent, field.name);
|
|
150
|
+
|
|
151
|
+
let last_version = -1;
|
|
152
|
+
let last_update_time = 0;
|
|
153
|
+
let last_update_duration = 0;
|
|
154
|
+
|
|
155
|
+
const view_container = new EmptyView({
|
|
156
|
+
css:{
|
|
157
|
+
width: "min-content",
|
|
158
|
+
height:"min-content"
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const canvas_view = new CanvasView();
|
|
163
|
+
canvas_view.css({
|
|
164
|
+
background: 'black',
|
|
165
|
+
position: 'relative',
|
|
166
|
+
});
|
|
72
167
|
|
|
73
|
-
|
|
74
|
-
const
|
|
168
|
+
function draw() {
|
|
169
|
+
const draw_start_time = performance.now();
|
|
75
170
|
|
|
76
|
-
|
|
171
|
+
draw_sampler(sampler, canvas_view.el);
|
|
77
172
|
|
|
78
173
|
last_version = sampler.version;
|
|
79
174
|
|
|
@@ -84,7 +179,7 @@ export class Sampler2DEditor extends TypeEditor {
|
|
|
84
179
|
}
|
|
85
180
|
|
|
86
181
|
|
|
87
|
-
|
|
182
|
+
canvas_view.on.linked.add(try_update);
|
|
88
183
|
|
|
89
184
|
function try_update() {
|
|
90
185
|
if (sampler.version !== last_version) {
|
|
@@ -99,9 +194,28 @@ export class Sampler2DEditor extends TypeEditor {
|
|
|
99
194
|
|
|
100
195
|
const frameRunner = new FrameRunner(try_update);
|
|
101
196
|
|
|
102
|
-
|
|
103
|
-
|
|
197
|
+
canvas_view.on.linked.add(frameRunner.startup, frameRunner);
|
|
198
|
+
canvas_view.on.unlinked.add(frameRunner.shutdown, frameRunner);
|
|
199
|
+
|
|
200
|
+
//drop target
|
|
201
|
+
const allow_drop = true;
|
|
202
|
+
if (allow_drop) {
|
|
203
|
+
|
|
204
|
+
enable_drop(parent, canvas_view.el, field);
|
|
205
|
+
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const allow_download = true;
|
|
209
|
+
if (allow_download) {
|
|
210
|
+
canvas_view.el.addEventListener(MouseEvents.Click, () => {
|
|
211
|
+
downloadSampler2DAsPNG(sampler, field.name);
|
|
212
|
+
});
|
|
213
|
+
// add download marker
|
|
214
|
+
view_container.addClass('downloadable');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
view_container.addChild(canvas_view);
|
|
104
218
|
|
|
105
|
-
return
|
|
219
|
+
return view_container;
|
|
106
220
|
}
|
|
107
221
|
}
|
|
@@ -3,6 +3,12 @@ import { convertTexture2Sampler2D } from "../../../../../engine/graphics/texture
|
|
|
3
3
|
import { Sampler2D } from "../../../../../engine/graphics/texture/sampler/Sampler2D.js";
|
|
4
4
|
import { CanvasView } from "../../../../../view/elements/CanvasView.js";
|
|
5
5
|
import sampler2D2Canvas from "../../../../../engine/graphics/texture/sampler/Sampler2D2Canvas.js";
|
|
6
|
+
import { MouseEvents } from "../../../../../engine/input/devices/events/MouseEvents.js";
|
|
7
|
+
import { downloadSampler2DAsPNG } from "../../../../../engine/graphics/texture/sampler/downloadSamplerAsPNG.js";
|
|
8
|
+
import EmptyView from "../../../../../view/elements/EmptyView.js";
|
|
9
|
+
import { FrameRunner } from "../../../../../engine/graphics/FrameRunner.js";
|
|
10
|
+
|
|
11
|
+
const UPDATE_DELAY = 200;
|
|
6
12
|
|
|
7
13
|
export class TextureEditor extends TypeEditor {
|
|
8
14
|
inline = true;
|
|
@@ -10,7 +16,7 @@ export class TextureEditor extends TypeEditor {
|
|
|
10
16
|
build(parent, field, registry) {
|
|
11
17
|
const size = 32;
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
let texture = field.adapter.read(parent, field.name);
|
|
14
20
|
let sampler;
|
|
15
21
|
if (texture) {
|
|
16
22
|
|
|
@@ -21,12 +27,84 @@ export class TextureEditor extends TypeEditor {
|
|
|
21
27
|
sampler.fill_channel(3, 255);
|
|
22
28
|
}
|
|
23
29
|
|
|
30
|
+
const vContainer = new EmptyView({
|
|
31
|
+
css: {
|
|
32
|
+
width: "min-content",
|
|
33
|
+
height: "min-content"
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
24
37
|
const canvasView = new CanvasView();
|
|
38
|
+
canvasView.css({
|
|
39
|
+
position: "relative",
|
|
40
|
+
background: 'black'
|
|
41
|
+
});
|
|
42
|
+
vContainer.addChild(canvasView);
|
|
25
43
|
|
|
26
44
|
canvasView.size.set(sampler.width, sampler.height);
|
|
27
45
|
|
|
28
|
-
sampler2D2Canvas(sampler, 1, 0, canvasView.el);
|
|
29
46
|
|
|
30
|
-
|
|
47
|
+
let last_version = -1;
|
|
48
|
+
let last_update_time = 0;
|
|
49
|
+
let last_update_duration = 0;
|
|
50
|
+
|
|
51
|
+
function draw() {
|
|
52
|
+
const draw_start_time = performance.now();
|
|
53
|
+
|
|
54
|
+
sampler = convertTexture2Sampler2D(texture, size, size);
|
|
55
|
+
sampler2D2Canvas(sampler, 1, 0, canvasView.el);
|
|
56
|
+
|
|
57
|
+
last_version = texture.version;
|
|
58
|
+
|
|
59
|
+
const draw_end_time = performance.now();
|
|
60
|
+
last_update_duration = draw_end_time - draw_start_time;
|
|
61
|
+
|
|
62
|
+
last_update_time = draw_end_time;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
function try_update() {
|
|
67
|
+
const time_now = performance.now();
|
|
68
|
+
|
|
69
|
+
if ((time_now - last_update_time) < UPDATE_DELAY) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
texture = field.adapter.read(parent, field.name);
|
|
74
|
+
|
|
75
|
+
if (texture === undefined || texture === null) {
|
|
76
|
+
sampler.fill(0);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (texture.version !== last_version) {
|
|
81
|
+
draw();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const frameRunner = new FrameRunner(try_update);
|
|
86
|
+
|
|
87
|
+
canvasView.on.linked.add(frameRunner.startup, frameRunner);
|
|
88
|
+
canvasView.on.unlinked.add(frameRunner.shutdown, frameRunner);
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
const allow_download = true;
|
|
92
|
+
if (allow_download) {
|
|
93
|
+
vContainer.el.addEventListener(MouseEvents.Click, () => {
|
|
94
|
+
const texture = field.adapter.read(parent, field.name);
|
|
95
|
+
if (texture === undefined || texture == null) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const sampler = convertTexture2Sampler2D(texture);
|
|
100
|
+
|
|
101
|
+
downloadSampler2DAsPNG(sampler, field.name);
|
|
102
|
+
});
|
|
103
|
+
// add download marker
|
|
104
|
+
vContainer.addClass('downloadable');
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
return vContainer;
|
|
31
109
|
}
|
|
32
110
|
}
|
|
@@ -30,7 +30,6 @@ import { SplatMapping } from "./splat/SplatMapping.js";
|
|
|
30
30
|
import { OffsetScaleTransform2D } from "./OffsetScaleTransform2D.js";
|
|
31
31
|
import { GridTransformKind } from "./GridTransformKind.js";
|
|
32
32
|
import { makeTerrainWorkerProxy } from "./makeTerrainWorkerProxy.js";
|
|
33
|
-
import { MeepSettings } from "../../../MeepSettings.js";
|
|
34
33
|
import { loadLegacyTerrainLayers } from "./layers/loadLegacyTerrainLayers.js";
|
|
35
34
|
import { TerrainFlags } from "./TerrainFlags.js";
|
|
36
35
|
import { IllegalStateException } from "../../../../core/fsm/exceptions/IllegalStateException.js";
|
|
@@ -798,8 +797,6 @@ class Terrain {
|
|
|
798
797
|
//
|
|
799
798
|
this.overlay.size.copy(this.size);
|
|
800
799
|
|
|
801
|
-
this.overlay.tileImage.set(MeepSettings.ecs.Terrain['tile-decal']);
|
|
802
|
-
|
|
803
800
|
this.__tiles.totalSize.copy(this.size);
|
|
804
801
|
this.__tiles.scale.set(this.gridScale, this.gridScale);
|
|
805
802
|
this.__tiles.resolution.set(this.resolution);
|
|
@@ -960,12 +957,19 @@ class Terrain {
|
|
|
960
957
|
this.layers.fromJSON(opt.layers);
|
|
961
958
|
this.splat.fromJSON(opt.splat);
|
|
962
959
|
|
|
960
|
+
if (opt.overlayTileImage !== undefined) {
|
|
961
|
+
|
|
962
|
+
this.overlay.baseTileImage(opt.overlayTileImage);
|
|
963
|
+
|
|
964
|
+
}
|
|
965
|
+
|
|
963
966
|
|
|
964
967
|
// debugSamplers(this);
|
|
965
968
|
this.build(engine.assetManager);
|
|
966
969
|
}
|
|
967
970
|
|
|
968
971
|
toJSON() {
|
|
972
|
+
|
|
969
973
|
const result = {
|
|
970
974
|
size: this.size.toJSON(),
|
|
971
975
|
scale: this.gridScale,
|
|
@@ -974,7 +978,8 @@ class Terrain {
|
|
|
974
978
|
preview: this.preview.toJSON(),
|
|
975
979
|
heights: this.samplerHeight.toJSON(),
|
|
976
980
|
layers: this.layers.toJSON(),
|
|
977
|
-
splat: this.splat.toJSON()
|
|
981
|
+
splat: this.splat.toJSON(),
|
|
982
|
+
overlayTileImage: this.overlay.baseTileImage
|
|
978
983
|
};
|
|
979
984
|
|
|
980
985
|
return result;
|
|
@@ -16,6 +16,7 @@ import { uint82float } from "../../../../core/binary/uint82float.js";
|
|
|
16
16
|
import { float2uint8 } from "../../../../core/binary/float2uint8.js";
|
|
17
17
|
import { isTypedArray } from "../../../../core/collection/array/typed/isTypedArray.js";
|
|
18
18
|
import { array_copy } from "../../../../core/collection/array/copyArray.js";
|
|
19
|
+
import { WHITE_PIXEL_DATA_URL } from "../../../graphics/WHITE_PIXEL_DATA_URL.js";
|
|
19
20
|
|
|
20
21
|
class Context {
|
|
21
22
|
/**
|
|
@@ -48,7 +49,6 @@ class Context {
|
|
|
48
49
|
|
|
49
50
|
const COLOR_UINT_8_TRANSPARENT = [0, 0, 0, 0];
|
|
50
51
|
|
|
51
|
-
|
|
52
52
|
export class TerrainOverlay {
|
|
53
53
|
/**
|
|
54
54
|
*
|
|
@@ -69,11 +69,11 @@ export class TerrainOverlay {
|
|
|
69
69
|
*/
|
|
70
70
|
this.size = new Vector2(size.x, size.y);
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
/**
|
|
73
73
|
*
|
|
74
74
|
* @type {ObservedString}
|
|
75
75
|
*/
|
|
76
|
-
this.tileImage = new ObservedString(
|
|
76
|
+
this.tileImage = new ObservedString(WHITE_PIXEL_DATA_URL);
|
|
77
77
|
|
|
78
78
|
/**
|
|
79
79
|
*
|
|
@@ -116,6 +116,26 @@ export class TerrainOverlay {
|
|
|
116
116
|
});
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
+
/**
|
|
120
|
+
*
|
|
121
|
+
* @returns {string}
|
|
122
|
+
*/
|
|
123
|
+
get baseTileImage(){
|
|
124
|
+
return this.stack.length === 0 ? this.tileImage.getValue() : this.stack[0].tileImage
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
*
|
|
129
|
+
* @param {string} v
|
|
130
|
+
*/
|
|
131
|
+
set baseTileImage(v){
|
|
132
|
+
if (this.stack.length === 0) {
|
|
133
|
+
this.tileImage.set(v);
|
|
134
|
+
} else {
|
|
135
|
+
this.stack[0].tileImage = v;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
119
139
|
/**
|
|
120
140
|
* @returns {HTMLCanvasElement}
|
|
121
141
|
*/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const WHITE_PIXEL_DATA_URL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAA1JREFUGFdj+P///38ACfsD/QVDRcoAAAAASUVORK5CYII=";
|
|
@@ -70,7 +70,7 @@ import { BasicMaterialDefinition } from "./tube/BasicMaterialDefinition.js";
|
|
|
70
70
|
import '../../../../../../../css/game.scss';
|
|
71
71
|
import { GizmoRenderingPlugin } from "../../render/gizmo/GizmoRenderingPlugin.js";
|
|
72
72
|
import { PathNormalType } from "./tube/PathNormalType.js";
|
|
73
|
-
import { Camera
|
|
73
|
+
import { Camera } from "../camera/Camera.js";
|
|
74
74
|
|
|
75
75
|
const engineHarness = new EngineHarness();
|
|
76
76
|
|
|
@@ -74,6 +74,7 @@ export function build_merge_graph(leaves) {
|
|
|
74
74
|
const connection_weight = computePatchMergeScore(leaf, neighbour);
|
|
75
75
|
|
|
76
76
|
assert.isNumber(connection_weight, 'connection_weight');
|
|
77
|
+
assert.notNaN(connection_weight, 'connection_weight');
|
|
77
78
|
assert.isFiniteNumber(connection_weight, 'connection_weight');
|
|
78
79
|
|
|
79
80
|
const edge = new WeightedEdge(node_leaf, node_neighbour);
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { ConicRay } from "../../../../../core/geom/ConicRay.js";
|
|
2
2
|
import { compute_bounding_cone_of_2_cones } from "../../../../../core/geom/3d/cone/compute_bounding_cone_of_2_cones.js";
|
|
3
3
|
import { compute_patches_shared_vertex_count } from "./compute_patches_shared_vertex_count.js";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
compute_bounding_sphere_of_2_spheres
|
|
6
|
+
} from "../../../../../core/geom/3d/compute_bounding_sphere_of_2_spheres.js";
|
|
5
7
|
import { max2 } from "../../../../../core/math/max2.js";
|
|
6
8
|
import { min2 } from "../../../../../core/math/min2.js";
|
|
9
|
+
import { assert } from "../../../../../core/assert.js";
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
/**
|
|
@@ -74,6 +77,12 @@ function compute_sphere_volume(r) {
|
|
|
74
77
|
* @return {number}
|
|
75
78
|
*/
|
|
76
79
|
function normalized_difference(a, b) {
|
|
80
|
+
assert.isNumber(a, 'a');
|
|
81
|
+
assert.isNumber(b, 'a');
|
|
82
|
+
|
|
83
|
+
assert.notNaN(a,'a');
|
|
84
|
+
assert.notNaN(b,'b');
|
|
85
|
+
|
|
77
86
|
return Math.abs(a - b) / (max2(a, b) + 0.0001);
|
|
78
87
|
}
|
|
79
88
|
|
|
@@ -85,10 +94,13 @@ function normalized_difference(a, b) {
|
|
|
85
94
|
*/
|
|
86
95
|
export function computePatchMergeScore(a, b) {
|
|
87
96
|
// compute common neighbours
|
|
88
|
-
const
|
|
97
|
+
const a_neighbours = a.neighbours;
|
|
98
|
+
const b_neighbours = b.neighbours;
|
|
99
|
+
|
|
100
|
+
const common_neighbours = array_compute_common_element_count(a_neighbours, b_neighbours);
|
|
89
101
|
|
|
90
102
|
// normalize neighbour count
|
|
91
|
-
const common_neighbour_score = common_neighbours / (min2(
|
|
103
|
+
const common_neighbour_score = common_neighbours / (min2(a_neighbours.length, b_neighbours.length) + 0.01);
|
|
92
104
|
|
|
93
105
|
// prefer merging patches of similar LOD level, this creates a more flat hierarchy
|
|
94
106
|
const lod_score = 1 - normalized_difference(a.lod, b.lod);
|
|
@@ -123,10 +135,12 @@ export function computePatchMergeScore(a, b) {
|
|
|
123
135
|
*/
|
|
124
136
|
const shared_vertex_count = compute_patches_shared_vertex_count(a, b);
|
|
125
137
|
|
|
126
|
-
|
|
138
|
+
const result = similar_volume_score * 0.01
|
|
127
139
|
+ shared_vertex_count
|
|
128
140
|
+ normal_score * 0.001
|
|
129
141
|
+ common_neighbour_score
|
|
130
142
|
+ lod_score * 0.1
|
|
131
143
|
+ volume_score;
|
|
144
|
+
|
|
145
|
+
return result;
|
|
132
146
|
}
|
|
@@ -91,6 +91,14 @@ export class GLTFAssetTransformer extends AssetTransformer {
|
|
|
91
91
|
* @private
|
|
92
92
|
*/
|
|
93
93
|
this.__active_mesh_micron_cache = [];
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @deprecated
|
|
97
|
+
* Whether override mesh will be created for the asset, this is generally outdated
|
|
98
|
+
* @type {boolean}
|
|
99
|
+
* @private
|
|
100
|
+
*/
|
|
101
|
+
this.__settings_build_override_mesh = false;
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
/**
|
|
@@ -198,7 +206,7 @@ export class GLTFAssetTransformer extends AssetTransformer {
|
|
|
198
206
|
*/
|
|
199
207
|
const root = source.create();
|
|
200
208
|
|
|
201
|
-
await this.__load_mesh_micron_data(source.gltf,asset_description);
|
|
209
|
+
await this.__load_mesh_micron_data(source.gltf, asset_description);
|
|
202
210
|
|
|
203
211
|
// attempt to load existing micron geometries
|
|
204
212
|
await async_traverse_three_object(root, this.__visitObjectToLoadMicron, this, {
|
|
@@ -212,12 +220,14 @@ export class GLTFAssetTransformer extends AssetTransformer {
|
|
|
212
220
|
return source;
|
|
213
221
|
}
|
|
214
222
|
|
|
215
|
-
|
|
216
|
-
|
|
223
|
+
if (this.__settings_build_override_mesh) {
|
|
224
|
+
const micron_root = await convert_three_object_to_micron(root.clone(), this.__cache);
|
|
225
|
+
micron_root.boundingSphere = root.boundingSphere;
|
|
217
226
|
|
|
218
|
-
|
|
227
|
+
source.override_mesh = micron_root;
|
|
219
228
|
|
|
220
|
-
|
|
229
|
+
traverseThreeObject(micron_root, ensureProxy);
|
|
230
|
+
}
|
|
221
231
|
|
|
222
232
|
return source;
|
|
223
233
|
}
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
* @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
13
|
* @returns {HTMLCanvasElement} canvas
|
|
14
14
|
*/
|
|
15
|
-
function convertSampler2D2Canvas(sampler, scale, offset, canvas, fillDD) {
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
function convertSampler2D2Canvas(sampler, scale=255, offset=0, canvas, fillDD) {
|
|
16
|
+
const source_data = sampler.data;
|
|
17
|
+
|
|
18
18
|
//generate canvas
|
|
19
19
|
if (canvas === undefined) {
|
|
20
20
|
canvas = document.createElement("canvas");
|
|
@@ -39,11 +39,12 @@ function convertSampler2D2Canvas(sampler, scale, offset, canvas, fillDD) {
|
|
|
39
39
|
const imageData = context.createImageData(width, height);
|
|
40
40
|
const array = imageData.data;
|
|
41
41
|
//
|
|
42
|
-
|
|
42
|
+
const source_channel_count = sampler.itemSize;
|
|
43
|
+
if (source_channel_count === 4 && offset === 0 && scale === 1) {
|
|
43
44
|
// shortcut or straight forward case
|
|
44
|
-
array.set(
|
|
45
|
+
array.set(source_data);
|
|
45
46
|
} else {
|
|
46
|
-
if (
|
|
47
|
+
if (source_channel_count < 4) {
|
|
47
48
|
//sampler lacks alpha channel, set alpha values to fully opaque
|
|
48
49
|
const n = width * height * 4;
|
|
49
50
|
|
|
@@ -53,17 +54,44 @@ function convertSampler2D2Canvas(sampler, scale, offset, canvas, fillDD) {
|
|
|
53
54
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
|
-
if (fillDD === undefined) {
|
|
57
|
-
fillDD = sampler.makeArrayFiller(scale, offset);
|
|
58
|
-
}
|
|
59
57
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
for (let
|
|
63
|
-
|
|
64
|
-
|
|
58
|
+
if (source_channel_count === 1) {
|
|
59
|
+
let index = 0;
|
|
60
|
+
for (let y = 0; y < height; y++) {
|
|
61
|
+
for (let x = 0; x < width; x++) {
|
|
62
|
+
const texel_address = (y * width + x);
|
|
63
|
+
|
|
64
|
+
const source_value = source_data[texel_address];
|
|
65
|
+
const transformed_value = Math.round((source_value + offset) * scale);
|
|
66
|
+
|
|
67
|
+
// write identical RGB for grayscale image
|
|
68
|
+
array[index + 0] = transformed_value;
|
|
69
|
+
array[index + 1] = transformed_value;
|
|
70
|
+
array[index + 2] = transformed_value;
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
index += 4;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
} else {
|
|
77
|
+
|
|
78
|
+
let index = 0;
|
|
79
|
+
for (let y = 0; y < height; y++) {
|
|
80
|
+
for (let x = 0; x < width; x++) {
|
|
81
|
+
const texel_address = (y * width + x) * source_channel_count;
|
|
82
|
+
|
|
83
|
+
for (let i = 0; i < source_channel_count; i++) {
|
|
84
|
+
const source_value = source_data[texel_address + i];
|
|
85
|
+
const transformed_value = Math.round((source_value + offset) * scale);
|
|
86
|
+
array[index + i] = transformed_value;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
index += 4;
|
|
91
|
+
}
|
|
65
92
|
}
|
|
66
93
|
}
|
|
94
|
+
|
|
67
95
|
}
|
|
68
96
|
|
|
69
97
|
context.putImageData(imageData, 0, 0);
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import convertSampler2D2Canvas from "./Sampler2D2Canvas.js";
|
|
2
|
+
import {
|
|
3
|
+
sampler2d_compute_texel_value_conversion_scale_to_uint8
|
|
4
|
+
} from "./sampler2d_compute_texel_value_conversion_scale_to_uint8.js";
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
*
|
|
@@ -11,7 +14,10 @@ export function convertSampler2D2DataURL(sampler) {
|
|
|
11
14
|
|
|
12
15
|
var ctx = canvasElement.getContext("2d");
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
|
|
18
|
+
const { scale, offset } = sampler2d_compute_texel_value_conversion_scale_to_uint8(sampler);
|
|
19
|
+
|
|
20
|
+
convertSampler2D2Canvas(sampler, scale, offset, canvasElement);
|
|
15
21
|
|
|
16
22
|
return ctx.canvas.toDataURL('image/png');
|
|
17
23
|
|
package/engine/graphics/texture/sampler/sampler2d_compute_texel_value_conversion_scale_to_uint8.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { DataType } from "../../../../core/collection/table/DataType.js";
|
|
2
|
+
import { min2 } from "../../../../core/math/min2.js";
|
|
3
|
+
import { max2 } from "../../../../core/math/max2.js";
|
|
4
|
+
import { isTypedArray } from "../../../../core/collection/array/typed/isTypedArray.js";
|
|
5
|
+
import { typedArrayToDataType } from "../../../../core/collection/array/typedArrayToDataType.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param {Sampler2D} sampler
|
|
10
|
+
* @returns {{offset: number, scale: number}}
|
|
11
|
+
*/
|
|
12
|
+
export function sampler2d_compute_texel_value_conversion_scale_to_uint8(sampler) {
|
|
13
|
+
|
|
14
|
+
let dataType;
|
|
15
|
+
|
|
16
|
+
if (isTypedArray(sampler.data)) {
|
|
17
|
+
dataType = typedArrayToDataType(sampler.data);
|
|
18
|
+
} else {
|
|
19
|
+
// plain numeric array
|
|
20
|
+
dataType = DataType.Float32;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let min = 0, max = 0;
|
|
24
|
+
|
|
25
|
+
if (dataType === DataType.Uint8) {
|
|
26
|
+
min = 0;
|
|
27
|
+
max = 255;
|
|
28
|
+
} else {
|
|
29
|
+
// unknown input type, compute min and max
|
|
30
|
+
min = Infinity;
|
|
31
|
+
max = -Infinity;
|
|
32
|
+
for (let i = 0; i < sampler.itemSize; i++) {
|
|
33
|
+
|
|
34
|
+
min = min2(min, sampler.computeMin(i).value)
|
|
35
|
+
max = max2(min, sampler.computeMax(i).value)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const span = max - min;
|
|
40
|
+
|
|
41
|
+
const scale = span === 0 ? 0 : 255 / span;
|
|
42
|
+
const offset = min;
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
scale, offset
|
|
46
|
+
};
|
|
47
|
+
}
|
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.39.
|
|
8
|
+
"version": "2.39.14",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|
package/view/View.js
CHANGED
|
@@ -26,7 +26,7 @@ function setElementTransform(domElement, position, scale, rotation) {
|
|
|
26
26
|
|
|
27
27
|
const m3 = scratch_m3_0;
|
|
28
28
|
|
|
29
|
-
m3_cm_compose_transform(m3, position.x, position.y, scale.x, scale.y,0,0, rotation);
|
|
29
|
+
m3_cm_compose_transform(m3, position.x, position.y, scale.x, scale.y, 0, 0, rotation);
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
/*
|
|
@@ -644,7 +644,7 @@ class View {
|
|
|
644
644
|
* @param {string} name
|
|
645
645
|
*/
|
|
646
646
|
addClass(name) {
|
|
647
|
-
assert.
|
|
647
|
+
assert.isString(name, 'name');
|
|
648
648
|
|
|
649
649
|
this.el.classList.add(name);
|
|
650
650
|
}
|
|
@@ -660,7 +660,7 @@ class View {
|
|
|
660
660
|
for (let i = 0; i < n; i++) {
|
|
661
661
|
const name = names[i];
|
|
662
662
|
|
|
663
|
-
assert.
|
|
663
|
+
assert.isString(name, 'name');
|
|
664
664
|
|
|
665
665
|
classList.add(name);
|
|
666
666
|
}
|