@woosh/meep-engine 2.33.76 → 2.34.3
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/collection/Set.js +0 -61
- package/core/collection/array/arrayIndexByEquality.js +20 -0
- package/core/collection/array/arraySetDiff.js +42 -0
- package/core/collection/array/arraySetSortingDiff.js +67 -0
- package/core/collection/array/arraySetSortingDiff.spec.js +74 -0
- package/core/collection/array/array_filter_by_multiple.js +36 -0
- package/core/collection/array/weightedRandomFromArray.js +9 -5
- package/core/collection/list/FilteredListProjection.js +1 -1
- package/core/collection/list/List.js +2 -1
- package/core/geom/3d/topology/compareEdges.js +16 -0
- package/core/geom/3d/topology/compareFaces.js +9 -0
- package/core/geom/3d/topology/compareVertices.js +9 -0
- package/core/geom/3d/topology/computeTopoMeshVertexDuplicates.js +25 -6
- package/core/geom/3d/topology/expandConnectivityByLocality.js +35 -19
- package/core/geom/Vector2.js +7 -2
- package/core/geom/Vector3.js +2 -2
- package/core/geom/v3_angle_between.js +3 -1
- package/editor/Editor.js +2 -2
- package/editor/view/ecs/components/items/ItemContainerController.stories.js +1 -1
- package/engine/EngineHarness.js +0 -1
- package/engine/asset/loaders/image/ImageDecoderWorker.js +3 -2
- package/engine/asset/loaders/image/ImageRGBADataAsset.js +2 -6
- package/engine/asset/loaders/image/ImageRGBADataLoader.js +18 -2
- package/engine/asset/loaders/image/codec/NativeImageDecoder.js +2 -1
- package/engine/asset/loaders/image/png/PNG.js +3 -2
- package/engine/asset/loaders/image/png/PNGReader.js +1 -0
- package/engine/ecs/EntityComponentDataset.js +1 -1
- package/engine/ecs/storage/BinaryBufferSerializer.js +2 -2
- package/engine/ecs/terrain/ecs/layers/TerrainLayers.js +9 -0
- package/engine/ecs/terrain/ecs/splat/SplatMapping.js +72 -26
- package/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +1 -2
- package/engine/graphics/ecs/highlight/system/MeshHighlightSystem.d.ts +3 -2
- package/engine/graphics/ecs/highlight/system/RenderableHighlightSystem.d.ts +3 -1
- package/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.d.ts +8 -0
- package/engine/graphics/ecs/highlight/system/ShadedGeometryHighlightSystem.js +180 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +74 -16
- package/engine/graphics/ecs/mesh-v2/ShadedGeometryFlags.js +7 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +9 -0
- package/engine/graphics/ecs/mesh-v2/prototypeShadedGeometry.js +4 -2
- package/engine/graphics/geometry/VertexDataSpec.js +20 -0
- package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +41 -1
- package/engine/graphics/micron/format/MicronGeometry.d.ts +6 -0
- package/engine/graphics/micron/format/MicronGeometry.js +156 -4
- package/engine/graphics/micron/plugin/MicronRenderPlugin.js +10 -1
- package/engine/graphics/particles/particular/engine/parameter/ParticleParameter.js +7 -2
- package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +3 -2
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +7 -3
- package/engine/graphics/texture/sampler/Sampler2D.js +2 -0
- package/engine/graphics/texture/sampler/downsampleSampler2D.js +3 -1
- package/engine/graphics/texture/sampler/genericResampleSampler2D.js +67 -0
- package/engine/graphics/texture/sampler/scaleSampler2D.js +29 -35
- package/engine/graphics/texture/sampler/upsampleSampler2D.js +47 -0
- package/generation/filtering/numeric/CellFilterReadGridLayer.js +2 -2
- package/generation/filtering/numeric/math/CellFilterSaturate.js +24 -0
- package/package.json +1 -1
- package/samples/terrain/editor.js +346 -0
- package/samples/terrain/from_image.js +289 -0
- package/samples/terrain/from_image_2.js +219 -0
- package/view/controller/controls/NativeListController.js +6 -3
- package/view/elements/radial/RadialMenu.js +1 -1
- package/engine/graphics/texture/sampler/debug/paintSamplerOnHTML.js +0 -32
- package/generation/theme/TerrainThemeApplicator.js +0 -6
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { EngineHarness } from "../../engine/EngineHarness.js";
|
|
2
|
+
import EmptyView from "../../view/elements/EmptyView.js";
|
|
3
|
+
import { EngineConfiguration } from "../../engine/EngineConfiguration.js";
|
|
4
|
+
import { buildCubeURLs } from "../../engine/graphics/texture/cubemap/buildCubeURLs.js";
|
|
5
|
+
import { ArrayBufferLoader } from "../../engine/asset/loaders/ArrayBufferLoader.js";
|
|
6
|
+
import { TerrainFlags } from "../../engine/ecs/terrain/ecs/TerrainFlags.js";
|
|
7
|
+
import Signal from "../../core/events/signal/Signal.js";
|
|
8
|
+
import { NativeListController } from "../../view/controller/controls/NativeListController.js";
|
|
9
|
+
import { TerrainLayer } from "../../engine/ecs/terrain/ecs/layers/TerrainLayer.js";
|
|
10
|
+
import CheckersTextureURI from "../../engine/graphics/texture/CheckersTextureURI.js";
|
|
11
|
+
import { obtainTerrain } from "../../engine/ecs/terrain/util/obtainTerrain.js";
|
|
12
|
+
import { Cache } from "../../core/cache/Cache.js";
|
|
13
|
+
import { computeStringHash } from "../../core/primitives/strings/computeStringHash.js";
|
|
14
|
+
import { noop, strictEquals } from "../../core/function/Functions.js";
|
|
15
|
+
import { scaleSampler2D } from "../../engine/graphics/texture/sampler/scaleSampler2D.js";
|
|
16
|
+
import { Sampler2D } from "../../engine/graphics/texture/sampler/Sampler2D.js";
|
|
17
|
+
import { DataType } from "../../core/collection/table/DataType.js";
|
|
18
|
+
import { compute_typed_array_constructor_from_data_type } from "../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
|
|
19
|
+
import { copy_Sampler2D_channel_data } from "../../engine/graphics/texture/sampler/copy_Sampler2D_channel_data.js";
|
|
20
|
+
import { TextureAssetLoader } from "../../engine/asset/loaders/texture/TextureAssetLoader.js";
|
|
21
|
+
import { CanvasView } from "../../view/elements/CanvasView.js";
|
|
22
|
+
import convertSampler2D2Canvas from "../../engine/graphics/texture/sampler/Sampler2D2Canvas.js";
|
|
23
|
+
|
|
24
|
+
const engineHarness = new EngineHarness();
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @param {Engine} engine
|
|
29
|
+
*/
|
|
30
|
+
function makeConfig(engine) {
|
|
31
|
+
|
|
32
|
+
const config = new EngineConfiguration();
|
|
33
|
+
|
|
34
|
+
config.addLoader('arraybuffer', new ArrayBufferLoader());
|
|
35
|
+
config.addLoader('texture', new TextureAssetLoader());
|
|
36
|
+
|
|
37
|
+
return config;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
class EditorTextureSlot {
|
|
41
|
+
constructor() {
|
|
42
|
+
this.onChanged = new Signal();
|
|
43
|
+
|
|
44
|
+
this.sampler = null;
|
|
45
|
+
|
|
46
|
+
this.__read = noop;
|
|
47
|
+
this.__write = noop;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @type {number}
|
|
52
|
+
*/
|
|
53
|
+
this.itemSize = 1;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
read() {
|
|
57
|
+
this.__read(this.sampler);
|
|
58
|
+
|
|
59
|
+
this.onChanged.send0();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
write() {
|
|
63
|
+
this.__write(this.sampler);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
*
|
|
68
|
+
* @param {(Sampler2D)=>any} read
|
|
69
|
+
* @param {(Sampler2D)=>any} write
|
|
70
|
+
* @param {number} [itemSize]
|
|
71
|
+
* @param {DataType} [dataType]
|
|
72
|
+
* @return {EditorTextureSlot}
|
|
73
|
+
*/
|
|
74
|
+
static from({ read, write, itemSize = 1, dataType = DataType.Uint8 }) {
|
|
75
|
+
const r = new EditorTextureSlot();
|
|
76
|
+
|
|
77
|
+
r.__read = read;
|
|
78
|
+
r.__write = write;
|
|
79
|
+
|
|
80
|
+
const TA = compute_typed_array_constructor_from_data_type(dataType);
|
|
81
|
+
|
|
82
|
+
r.sampler = new Sampler2D(new TA(itemSize), itemSize, 1, 1);
|
|
83
|
+
|
|
84
|
+
return r;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
class TextureLayerEditor {
|
|
89
|
+
constructor() {
|
|
90
|
+
this.index = 0;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @type {Terrain|null}
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
this.__terrain = null;
|
|
98
|
+
|
|
99
|
+
this.__splat = EditorTextureSlot.from({
|
|
100
|
+
read: (target) => {
|
|
101
|
+
const terrain = this.__terrain;
|
|
102
|
+
|
|
103
|
+
target.resize(terrain.splat.size.x, terrain.splat.size.y)
|
|
104
|
+
|
|
105
|
+
terrain.splat.readLayerToSampler(target, this.index, 0);
|
|
106
|
+
},
|
|
107
|
+
write: (source) => {
|
|
108
|
+
this.__terrain.splat.writeLayerFromSampler(source, this.index, 0);
|
|
109
|
+
},
|
|
110
|
+
itemSize: 1
|
|
111
|
+
});
|
|
112
|
+
this.__diffuse = EditorTextureSlot.from({
|
|
113
|
+
read: (target) => {
|
|
114
|
+
|
|
115
|
+
const layers = this.__terrain.layers;
|
|
116
|
+
|
|
117
|
+
const layer = layers.get(this.index);
|
|
118
|
+
|
|
119
|
+
target.resize(layer.diffuse.width, layer.diffuse.height);
|
|
120
|
+
copy_Sampler2D_channel_data(layer.diffuse, target);
|
|
121
|
+
},
|
|
122
|
+
write: (source) => {
|
|
123
|
+
const layer = this.__terrain.layers.get(this.index);
|
|
124
|
+
|
|
125
|
+
copy_Sampler2D_channel_data(source, layer.diffuse);
|
|
126
|
+
|
|
127
|
+
this.__terrain.layers.writeLayerDataIntoTexture(this.index);
|
|
128
|
+
},
|
|
129
|
+
itemSize: 3
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @param {Terrain} t
|
|
135
|
+
*/
|
|
136
|
+
set terrain(t) {
|
|
137
|
+
this.__terrain = t;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
init() {
|
|
141
|
+
this.__splat.read();
|
|
142
|
+
this.__diffuse.read();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
*
|
|
148
|
+
* @param {EditorTextureSlot} slot
|
|
149
|
+
*/
|
|
150
|
+
function makeTextureSlotView({ slot }) {
|
|
151
|
+
|
|
152
|
+
const preview = new CanvasView();
|
|
153
|
+
preview.size.set(64, 64);
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
function update() {
|
|
157
|
+
convertSampler2D2Canvas(slot.sampler, 1, 0, preview.el);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
preview.on.linked.add(update);
|
|
161
|
+
preview.bindSignal(slot.onChanged, update);
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
return preview;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
*
|
|
169
|
+
* @param {View} root
|
|
170
|
+
* @param {Terrain} terrain
|
|
171
|
+
* @param {Engine} engine
|
|
172
|
+
*/
|
|
173
|
+
function makeTerrainEditor(root, terrain, engine) {
|
|
174
|
+
/**
|
|
175
|
+
*
|
|
176
|
+
* @type {Cache<string, Sampler2D>}
|
|
177
|
+
*/
|
|
178
|
+
const PREVIEW_CACHE = new Cache({
|
|
179
|
+
keyHashFunction: computeStringHash,
|
|
180
|
+
keyEqualityFunction: strictEquals
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
const PREVIEW_SIZE = 64;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
*
|
|
187
|
+
* @param {string} url
|
|
188
|
+
* @return {Promise<Sampler2D>}
|
|
189
|
+
*/
|
|
190
|
+
async function getPreviewFromURL(url) {
|
|
191
|
+
if (PREVIEW_CACHE.contains(url)) {
|
|
192
|
+
return PREVIEW_CACHE.get(url);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const asset = await engine.assetManager.promise(url, 'image');
|
|
196
|
+
|
|
197
|
+
// check cache again, might have been loaded in the meanwhile
|
|
198
|
+
if (PREVIEW_CACHE.contains(url)) {
|
|
199
|
+
return PREVIEW_CACHE.get(url);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const source = asset.create();
|
|
203
|
+
|
|
204
|
+
const preview = Sampler2D.uint8(4, PREVIEW_SIZE, PREVIEW_SIZE);
|
|
205
|
+
|
|
206
|
+
scaleSampler2D(source, preview);
|
|
207
|
+
|
|
208
|
+
PREVIEW_CACHE.put(url, preview);
|
|
209
|
+
|
|
210
|
+
return preview;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
*
|
|
215
|
+
* @type {EditorTextureSlot|null}
|
|
216
|
+
*/
|
|
217
|
+
let active_slot = null;
|
|
218
|
+
|
|
219
|
+
function rebuild() {
|
|
220
|
+
// rebuild terrain
|
|
221
|
+
terrain.clearFlag(TerrainFlags.Built);
|
|
222
|
+
terrain.build(engine.assetManager);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function build_splat_editor() {
|
|
226
|
+
/**
|
|
227
|
+
*
|
|
228
|
+
* @type {Map<TerrainLayer, TextureLayerEditor>}
|
|
229
|
+
*/
|
|
230
|
+
const editors = new Map();
|
|
231
|
+
|
|
232
|
+
return new NativeListController({
|
|
233
|
+
model: terrain.layers.layers,
|
|
234
|
+
elementFactory() {
|
|
235
|
+
return TerrainLayer.from(CheckersTextureURI, 1, 1);
|
|
236
|
+
},
|
|
237
|
+
/**
|
|
238
|
+
*
|
|
239
|
+
* @param {TerrainLayer} layer
|
|
240
|
+
*/
|
|
241
|
+
elementViewFactory(layer) {
|
|
242
|
+
const e = new TextureLayerEditor();
|
|
243
|
+
|
|
244
|
+
editors.set(layer, e);
|
|
245
|
+
|
|
246
|
+
const layer_index = terrain.layers.layers.indexOf(layer);
|
|
247
|
+
|
|
248
|
+
e.terrain = terrain;
|
|
249
|
+
e.index = layer_index;
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
e.init();
|
|
253
|
+
|
|
254
|
+
const view = new EmptyView();
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
view.addChild(makeTextureSlotView({
|
|
258
|
+
slot: e.__diffuse
|
|
259
|
+
}));
|
|
260
|
+
view.addChild(makeTextureSlotView({
|
|
261
|
+
slot: e.__splat
|
|
262
|
+
}));
|
|
263
|
+
|
|
264
|
+
view.bindSignal(layer.onChanged, e.__diffuse.read, e.__diffuse);
|
|
265
|
+
|
|
266
|
+
return view;
|
|
267
|
+
},
|
|
268
|
+
operationAdd(list, el) {
|
|
269
|
+
terrain.layers.addLayer(el);
|
|
270
|
+
terrain.splat.addWeightLayer();
|
|
271
|
+
},
|
|
272
|
+
operationRemove(list, el) {
|
|
273
|
+
const index = terrain.layers.layers.indexOf(el);
|
|
274
|
+
terrain.layers.removeLayer(el);
|
|
275
|
+
terrain.splat.removeWeightLayer(index);
|
|
276
|
+
|
|
277
|
+
editors.delete(el);
|
|
278
|
+
|
|
279
|
+
// re-shuffle remaining editors
|
|
280
|
+
|
|
281
|
+
for (const [layer, editor] of editors) {
|
|
282
|
+
if (editor.index > index) {
|
|
283
|
+
editor.index--;
|
|
284
|
+
editor.init();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
root.addChild(build_splat_editor());
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
*
|
|
296
|
+
* @param {Engine} engine
|
|
297
|
+
* @return {string}
|
|
298
|
+
*/
|
|
299
|
+
async function main(engine) {
|
|
300
|
+
|
|
301
|
+
//disable drag and drop on game canvas
|
|
302
|
+
engine.graphics.domElement.addEventListener('dragover', (e) => e.preventDefault());
|
|
303
|
+
engine.graphics.domElement.addEventListener('drop', (e) => e.preventDefault());
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
EngineHarness.buildLights({ engine });
|
|
307
|
+
const camera = EngineHarness.buildCamera({ engine });
|
|
308
|
+
EngineHarness.buildOrbitalCameraController({ engine, cameraEntity: camera.entity })
|
|
309
|
+
|
|
310
|
+
await EngineHarness.buildTerrain({ engine });
|
|
311
|
+
|
|
312
|
+
const vMain = new EmptyView({ classList: ['ui-texture-testing-tool-view'] });
|
|
313
|
+
|
|
314
|
+
vMain.css({
|
|
315
|
+
position: "absolute",
|
|
316
|
+
left: "0",
|
|
317
|
+
top: "0",
|
|
318
|
+
pointerEvents: "initial"
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
makeTerrainEditor(vMain, obtainTerrain(engine.entityManager.dataset), engine);
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
document.body.appendChild(vMain.el);
|
|
325
|
+
vMain.link();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
*
|
|
331
|
+
* @param {EngineHarness} harness
|
|
332
|
+
*/
|
|
333
|
+
async function init(harness) {
|
|
334
|
+
|
|
335
|
+
const engine = harness.engine;
|
|
336
|
+
|
|
337
|
+
await makeConfig(engine).apply(engine);
|
|
338
|
+
|
|
339
|
+
await engine.graphics.loadEnvironmentMap(buildCubeURLs('data/textures/cubemaps/hip_miramar/32/', '.png'));
|
|
340
|
+
|
|
341
|
+
await harness.initialize();
|
|
342
|
+
|
|
343
|
+
main(engine);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
init(engineHarness);
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { EngineConfiguration } from "../../engine/EngineConfiguration.js";
|
|
2
|
+
import { EngineHarness } from "../../engine/EngineHarness.js";
|
|
3
|
+
import { GameAssetType } from "../../engine/asset/GameAssetType.js";
|
|
4
|
+
import { TextureAssetLoader } from "../../engine/asset/loaders/texture/TextureAssetLoader.js";
|
|
5
|
+
import Vector3 from "../../core/geom/Vector3.js";
|
|
6
|
+
import EntityBuilder from "../../engine/ecs/EntityBuilder.js";
|
|
7
|
+
import Terrain from "../../engine/ecs/terrain/ecs/Terrain.js";
|
|
8
|
+
import { ImageRGBADataLoader } from "../../engine/asset/loaders/image/ImageRGBADataLoader.js";
|
|
9
|
+
import TerrainSystem from "../../engine/ecs/terrain/ecs/TerrainSystem.js";
|
|
10
|
+
import WaterSystem from "../../engine/graphics/ecs/water/WaterSystem.js";
|
|
11
|
+
import Water from "../../engine/graphics/ecs/water/Water.js";
|
|
12
|
+
import { ThemeEngine } from "../../generation/theme/ThemeEngine.js";
|
|
13
|
+
import { Theme } from "../../generation/theme/Theme.js";
|
|
14
|
+
import { TerrainTheme } from "../../generation/theme/TerrainTheme.js";
|
|
15
|
+
import { AreaTheme } from "../../generation/theme/AreaTheme.js";
|
|
16
|
+
import { GridData } from "../../generation/grid/GridData.js";
|
|
17
|
+
import { TerrainLayerRule } from "../../generation/theme/TerrainLayerRule.js";
|
|
18
|
+
import { TerrainLayerDescription } from "../../generation/theme/TerrainLayerDescription.js";
|
|
19
|
+
import Vector2 from "../../core/geom/Vector2.js";
|
|
20
|
+
import { CellFilterLiteralFloat } from "../../generation/filtering/numeric/CellFilterLiteralFloat.js";
|
|
21
|
+
import { GridDataLayer } from "../../generation/grid/layers/GridDataLayer.js";
|
|
22
|
+
import { CellFilterReadGridLayer } from "../../generation/filtering/numeric/CellFilterReadGridLayer.js";
|
|
23
|
+
import { CellFilterSmoothStep } from "../../generation/filtering/numeric/math/CellFilterSmoothStep.js";
|
|
24
|
+
import { CellFilterOneMinus } from "../../generation/filtering/numeric/math/CellFilterOneMinus.js";
|
|
25
|
+
import { CellFilterMultiply } from "../../generation/filtering/numeric/math/algebra/CellFilterMultiply.js";
|
|
26
|
+
import { CellFilterCurvature } from "../../generation/filtering/numeric/complex/CellFilterCurvature.js";
|
|
27
|
+
import { CellFilterMax2 } from "../../generation/filtering/numeric/math/CellFilterMax2.js";
|
|
28
|
+
import { CellFilterMin2 } from "../../generation/filtering/numeric/math/CellFilterMin2.js";
|
|
29
|
+
import { AmbientOcclusionPostProcessEffect } from "../../engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js";
|
|
30
|
+
import { CellFilterAngleToNormal } from "../../generation/filtering/numeric/complex/CellFilterAngleToNormal.js";
|
|
31
|
+
import { CellFilterCache } from "../../generation/filtering/numeric/CellFilterCache.js";
|
|
32
|
+
|
|
33
|
+
const HEIGHT_RANGE = 100;
|
|
34
|
+
|
|
35
|
+
const eh = new EngineHarness();
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @param {Engine} engine
|
|
40
|
+
* @return {EngineConfiguration}
|
|
41
|
+
*/
|
|
42
|
+
function makeConfig(engine) {
|
|
43
|
+
const r = new EngineConfiguration();
|
|
44
|
+
|
|
45
|
+
// configure engine here, add systems, loaders etc.
|
|
46
|
+
r.addLoader(GameAssetType.Texture, new TextureAssetLoader());
|
|
47
|
+
r.addLoader(GameAssetType.Image, new ImageRGBADataLoader());
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
r.addSystem(new TerrainSystem(engine.graphics, engine.assetManager));
|
|
51
|
+
r.addSystem(new WaterSystem(engine.graphics));
|
|
52
|
+
|
|
53
|
+
r.addPlugin(AmbientOcclusionPostProcessEffect);
|
|
54
|
+
|
|
55
|
+
return r;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function makeTheme() {
|
|
59
|
+
const theme = new Theme();
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
const terrainTheme = new TerrainTheme();
|
|
63
|
+
|
|
64
|
+
const height = CellFilterReadGridLayer.from('height');
|
|
65
|
+
const curvature = CellFilterCurvature.from(height);
|
|
66
|
+
|
|
67
|
+
const slope = CellFilterAngleToNormal.from(height, Vector3.forward);
|
|
68
|
+
|
|
69
|
+
const filterNotVerySharpSlope = CellFilterCache.from(
|
|
70
|
+
CellFilterOneMinus.from(
|
|
71
|
+
CellFilterSmoothStep.from(
|
|
72
|
+
CellFilterLiteralFloat.from(Math.PI / 9),
|
|
73
|
+
CellFilterLiteralFloat.from(Math.PI / 5),
|
|
74
|
+
slope
|
|
75
|
+
)
|
|
76
|
+
)
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const main_dress_weights = CellFilterMin2.from(
|
|
80
|
+
CellFilterSmoothStep.from(
|
|
81
|
+
CellFilterLiteralFloat.from(0.125 * HEIGHT_RANGE),
|
|
82
|
+
CellFilterLiteralFloat.from(0.175 * HEIGHT_RANGE),
|
|
83
|
+
height
|
|
84
|
+
),
|
|
85
|
+
CellFilterOneMinus.from(curvature)
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
terrainTheme.rules.push(
|
|
89
|
+
// RIVER
|
|
90
|
+
TerrainLayerRule.from(
|
|
91
|
+
CellFilterOneMinus.from(
|
|
92
|
+
CellFilterSmoothStep.from(
|
|
93
|
+
CellFilterLiteralFloat.from(0.115 * HEIGHT_RANGE),
|
|
94
|
+
CellFilterLiteralFloat.from(0.125 * HEIGHT_RANGE),
|
|
95
|
+
height
|
|
96
|
+
)
|
|
97
|
+
),
|
|
98
|
+
TerrainLayerDescription.from({
|
|
99
|
+
diffuse: "data/textures/materials/water-pool-texture-seamless-and-free.jpg",
|
|
100
|
+
size: new Vector2(100, 100)
|
|
101
|
+
})
|
|
102
|
+
),
|
|
103
|
+
// WET AREAS
|
|
104
|
+
TerrainLayerRule.from(
|
|
105
|
+
CellFilterMax2.from(
|
|
106
|
+
CellFilterMultiply.from(
|
|
107
|
+
CellFilterSmoothStep.from(
|
|
108
|
+
CellFilterLiteralFloat.from(0.125 * HEIGHT_RANGE),
|
|
109
|
+
CellFilterLiteralFloat.from(0.15 * HEIGHT_RANGE),
|
|
110
|
+
height
|
|
111
|
+
),
|
|
112
|
+
CellFilterOneMinus.from(
|
|
113
|
+
CellFilterSmoothStep.from(
|
|
114
|
+
CellFilterLiteralFloat.from(0.175 * HEIGHT_RANGE),
|
|
115
|
+
CellFilterLiteralFloat.from(0.2 * HEIGHT_RANGE),
|
|
116
|
+
height
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
),
|
|
120
|
+
CellFilterSmoothStep.from(
|
|
121
|
+
CellFilterLiteralFloat.from(0.2),
|
|
122
|
+
CellFilterLiteralFloat.from(0.5),
|
|
123
|
+
curvature
|
|
124
|
+
)
|
|
125
|
+
),
|
|
126
|
+
TerrainLayerDescription.from({
|
|
127
|
+
diffuse: "data/textures/materials/terrain_township_set/512/Ground_1_dark.png",
|
|
128
|
+
size: new Vector2(40, 40)
|
|
129
|
+
})
|
|
130
|
+
),
|
|
131
|
+
// TOP SOIL
|
|
132
|
+
TerrainLayerRule.from(
|
|
133
|
+
CellFilterMultiply.from(
|
|
134
|
+
main_dress_weights,
|
|
135
|
+
filterNotVerySharpSlope
|
|
136
|
+
),
|
|
137
|
+
TerrainLayerDescription.from({
|
|
138
|
+
diffuse: "data/textures/materials/terrain_township_set/512/Grass_1.png",
|
|
139
|
+
size: new Vector2(40, 40)
|
|
140
|
+
})
|
|
141
|
+
),
|
|
142
|
+
// SLOPE SOIL
|
|
143
|
+
TerrainLayerRule.from(
|
|
144
|
+
CellFilterMultiply.from(
|
|
145
|
+
main_dress_weights,
|
|
146
|
+
CellFilterOneMinus.from(filterNotVerySharpSlope)
|
|
147
|
+
),
|
|
148
|
+
TerrainLayerDescription.from({
|
|
149
|
+
diffuse: "data/textures/materials/terrain_township_set/512/Grass_3.png",
|
|
150
|
+
size: new Vector2(40, 40)
|
|
151
|
+
})
|
|
152
|
+
)
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
theme.terrain = terrainTheme;
|
|
156
|
+
|
|
157
|
+
return theme;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
*
|
|
162
|
+
* @param {Engine} engine
|
|
163
|
+
*/
|
|
164
|
+
async function main(engine) {
|
|
165
|
+
const TERRAIN_SIZE = 256;
|
|
166
|
+
|
|
167
|
+
await EngineHarness.buildBasics({
|
|
168
|
+
engine,
|
|
169
|
+
enableWater: false,
|
|
170
|
+
enableTerrain: false,
|
|
171
|
+
focus: new Vector3(250, 0, 250),
|
|
172
|
+
yaw: -Math.PI,
|
|
173
|
+
pitch: 0.91,
|
|
174
|
+
distance: 770
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
*
|
|
179
|
+
* @type {EntityComponentDataset}
|
|
180
|
+
*/
|
|
181
|
+
const ecd = engine.entityManager.dataset;
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
const terrain = new Terrain();
|
|
185
|
+
terrain.size.set(TERRAIN_SIZE, TERRAIN_SIZE);
|
|
186
|
+
terrain.resolution = 2;
|
|
187
|
+
terrain.gridScale = 2;
|
|
188
|
+
terrain.splat.resize(TERRAIN_SIZE, TERRAIN_SIZE, 1);
|
|
189
|
+
terrain.splat.fillLayerWeights(0, 255);
|
|
190
|
+
|
|
191
|
+
// load height map
|
|
192
|
+
const asset = await engine.assetManager.promise('moicon/heightmap.png', 'image');
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
*
|
|
196
|
+
* @type {Sampler2D}
|
|
197
|
+
*/
|
|
198
|
+
const sampler = asset.create();
|
|
199
|
+
|
|
200
|
+
terrain.samplerHeight.resize(sampler.width, sampler.height);
|
|
201
|
+
const source_height_data = sampler.data;
|
|
202
|
+
const sampler_pixel_count = source_height_data.length;
|
|
203
|
+
const terrain_height_data = terrain.samplerHeight.data;
|
|
204
|
+
|
|
205
|
+
let divisor;
|
|
206
|
+
if (source_height_data instanceof Uint8Array) {
|
|
207
|
+
divisor = 255;
|
|
208
|
+
} else if (source_height_data instanceof Uint16Array) {
|
|
209
|
+
divisor = 65536 - 1;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
for (let i = 0; i < sampler_pixel_count; i++) {
|
|
213
|
+
const source_v = source_height_data[i];
|
|
214
|
+
|
|
215
|
+
const b0 = source_v & 0xFF;
|
|
216
|
+
const b1 = (source_v >> 8) & 0xFF;
|
|
217
|
+
|
|
218
|
+
let rotated_v;
|
|
219
|
+
rotated_v = b1 | (b0 << 8);
|
|
220
|
+
|
|
221
|
+
if (rotated_v <= 7000) {
|
|
222
|
+
rotated_v = 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
terrain_height_data[i] = (rotated_v / divisor) * HEIGHT_RANGE
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const grid = new GridData();
|
|
229
|
+
grid.resize(TERRAIN_SIZE, TERRAIN_SIZE);
|
|
230
|
+
|
|
231
|
+
//inject height map into grid layer
|
|
232
|
+
const layer = new GridDataLayer();
|
|
233
|
+
layer.id = 'height';
|
|
234
|
+
|
|
235
|
+
grid.addLayer(layer);
|
|
236
|
+
|
|
237
|
+
layer.sampler = terrain.samplerHeight;
|
|
238
|
+
|
|
239
|
+
const theme_engine = new ThemeEngine();
|
|
240
|
+
|
|
241
|
+
const areaTheme = new AreaTheme();
|
|
242
|
+
areaTheme.theme = makeTheme();
|
|
243
|
+
areaTheme.mask.resize(grid.width, grid.height);
|
|
244
|
+
areaTheme.mask.mask.data.fill(255);
|
|
245
|
+
areaTheme.mask.distanceField.data.fill(0);
|
|
246
|
+
areaTheme.mask.bounds.set(0, 0, grid.width, grid.height);
|
|
247
|
+
|
|
248
|
+
theme_engine.add(areaTheme);
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
terrain.build(engine.assetManager);
|
|
252
|
+
|
|
253
|
+
const water = new Water();
|
|
254
|
+
|
|
255
|
+
water.level.set(5);
|
|
256
|
+
water.shoreDepthTransition.set(0.1, 0.3);
|
|
257
|
+
water.scattering.set(3);
|
|
258
|
+
|
|
259
|
+
new EntityBuilder()
|
|
260
|
+
.add(terrain)
|
|
261
|
+
// .add(water)
|
|
262
|
+
.build(ecd);
|
|
263
|
+
|
|
264
|
+
const task = theme_engine.apply(grid, ecd);
|
|
265
|
+
|
|
266
|
+
const promise_load = engine.loadSlowTask(task);
|
|
267
|
+
|
|
268
|
+
engine.executor.runGroup(task);
|
|
269
|
+
|
|
270
|
+
await promise_load;
|
|
271
|
+
|
|
272
|
+
await terrain.buildLightMap(1);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
*
|
|
277
|
+
* @param {EngineHarness} harness
|
|
278
|
+
*/
|
|
279
|
+
async function init(harness) {
|
|
280
|
+
const engine = eh.engine;
|
|
281
|
+
|
|
282
|
+
await makeConfig(engine).apply(engine);
|
|
283
|
+
|
|
284
|
+
await eh.initialize();
|
|
285
|
+
|
|
286
|
+
main(engine);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
init(eh);
|