@woosh/meep-engine 2.33.76 → 2.34.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/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/view/ecs/components/items/ItemContainerController.stories.js +1 -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/terrain/ecs/splat/SplatMapping.js +38 -0
- 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/micron/build/buildMicronGeometryFromBufferGeometry.js +41 -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/from_image.js +289 -0
- package/samples/terrain/from_image_2.js +219 -0
- package/view/elements/radial/RadialMenu.js +1 -1
- package/generation/theme/TerrainThemeApplicator.js +0 -6
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { max2 } from "../../../../core/math/max2.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {Sampler2D} source
|
|
6
|
+
* @param {Sampler2D} target
|
|
7
|
+
*/
|
|
8
|
+
export function genericResampleSampler2D(source, target) {
|
|
9
|
+
const target_width = target.width;
|
|
10
|
+
const target_height = target.height;
|
|
11
|
+
|
|
12
|
+
// build kernel
|
|
13
|
+
|
|
14
|
+
// TODO add gaussian weights kernel for samples
|
|
15
|
+
|
|
16
|
+
const u_scale = source.width / target_width;
|
|
17
|
+
const v_scale = source.height / target_height;
|
|
18
|
+
|
|
19
|
+
const kernel_width = max2(1, Math.ceil(u_scale));
|
|
20
|
+
const kernel_height = max2(1, Math.ceil(v_scale));
|
|
21
|
+
|
|
22
|
+
const kernel_size = kernel_width * kernel_height;
|
|
23
|
+
|
|
24
|
+
const itemSize = source.itemSize;
|
|
25
|
+
|
|
26
|
+
const sample = new Float32Array(itemSize);
|
|
27
|
+
|
|
28
|
+
let column_index;
|
|
29
|
+
let row_index;
|
|
30
|
+
let k_y;
|
|
31
|
+
let k_x;
|
|
32
|
+
let i;
|
|
33
|
+
|
|
34
|
+
for (column_index = 0; column_index < target_height; column_index++) {
|
|
35
|
+
for (row_index = 0; row_index < target_width; row_index++) {
|
|
36
|
+
|
|
37
|
+
// figure out source offset
|
|
38
|
+
const source_x = row_index * u_scale;
|
|
39
|
+
const source_y = column_index * v_scale;
|
|
40
|
+
|
|
41
|
+
// reset sample
|
|
42
|
+
for (i = 0; i < itemSize; i++) {
|
|
43
|
+
sample[i] = 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// accumulate kernel samples
|
|
47
|
+
for (k_y = 0; k_y < kernel_height; k_y++) {
|
|
48
|
+
|
|
49
|
+
for (k_x = 0; k_x < kernel_width; k_x++) {
|
|
50
|
+
|
|
51
|
+
for (i = 0; i < itemSize; i++) {
|
|
52
|
+
sample[i] += source.sampleChannelBilinear(source_x + k_x, source_y + k_y, i);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (i = 0; i < itemSize; i++) {
|
|
59
|
+
// dilute sample
|
|
60
|
+
const channel_value = sample[i] / kernel_size;
|
|
61
|
+
// write out
|
|
62
|
+
target.data[(column_index * target_width + row_index) * itemSize + i] = channel_value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -1,47 +1,41 @@
|
|
|
1
1
|
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
import { downsampleSampler2D } from "./downsampleSampler2D.js";
|
|
3
|
+
import { Sampler2D } from "./Sampler2D.js";
|
|
4
|
+
import { upsampleSampler2D } from "./upsampleSampler2D.js";
|
|
5
|
+
import { genericResampleSampler2D } from "./genericResampleSampler2D.js";
|
|
2
6
|
|
|
3
7
|
/**
|
|
4
8
|
*
|
|
5
|
-
* @param {Sampler2D}
|
|
6
|
-
* @param {Sampler2D}
|
|
9
|
+
* @param {Sampler2D} input
|
|
10
|
+
* @param {Sampler2D} output
|
|
7
11
|
*/
|
|
8
|
-
export function scaleSampler2D(
|
|
9
|
-
const targetItemSize =
|
|
12
|
+
export function scaleSampler2D(input, output) {
|
|
13
|
+
const targetItemSize = output.itemSize;
|
|
10
14
|
|
|
11
|
-
assert.equal(
|
|
15
|
+
assert.equal(input.itemSize, targetItemSize, 'both source and target must have the same number of channels');
|
|
12
16
|
|
|
13
|
-
const targetWidth =
|
|
14
|
-
const targetHeight =
|
|
15
|
-
const sourceWidth =
|
|
16
|
-
const sourceHeight =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const target_data = target.data;
|
|
17
|
+
const targetWidth = output.width;
|
|
18
|
+
const targetHeight = output.height;
|
|
19
|
+
const sourceWidth = input.width;
|
|
20
|
+
const sourceHeight = input.height;
|
|
20
21
|
|
|
21
22
|
if (sourceWidth === targetWidth && sourceHeight === targetHeight) {
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
for (let y = 0; y < targetHeight; y++) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const sample_y = y * source_scale_y;
|
|
36
|
-
const target_row_address = y * targetRowSize;
|
|
37
|
-
|
|
38
|
-
for (let x = 0; x < targetWidth; x++) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const target_offset = target_row_address + x * targetItemSize;
|
|
42
|
-
|
|
43
|
-
source.sampleBilinear(x * source_scale_x, sample_y, target_data, target_offset);
|
|
44
|
-
|
|
23
|
+
// same dimensions, copy directly
|
|
24
|
+
output.data.set(input.data);
|
|
25
|
+
} else if (sourceWidth > targetWidth && sourceHeight > targetHeight) {
|
|
26
|
+
// downscaling
|
|
27
|
+
if (Number.isInteger(sourceWidth / targetWidth) && Number.isInteger(sourceHeight / targetHeight)) {
|
|
28
|
+
// dimensions are multiples of source/target
|
|
29
|
+
downsampleSampler2D(input, output);
|
|
30
|
+
} else {
|
|
31
|
+
// generic downsample
|
|
32
|
+
genericResampleSampler2D(input, output);
|
|
45
33
|
}
|
|
34
|
+
} else if (sourceWidth < targetWidth && sourceHeight < targetHeight) {
|
|
35
|
+
// upscaling
|
|
36
|
+
upsampleSampler2D(input, output);
|
|
37
|
+
} else {
|
|
38
|
+
// mixed resampling
|
|
39
|
+
genericResampleSampler2D(input, output);
|
|
46
40
|
}
|
|
47
41
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { assert } from "../../../../core/assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {Sampler2D} input
|
|
6
|
+
* @param {Sampler2D} output
|
|
7
|
+
*/
|
|
8
|
+
export function upsampleSampler2D(input, output) {
|
|
9
|
+
const targetItemSize = output.itemSize;
|
|
10
|
+
|
|
11
|
+
assert.equal(input.itemSize, targetItemSize, 'both source and target must have the same number of channels');
|
|
12
|
+
|
|
13
|
+
const targetWidth = output.width;
|
|
14
|
+
const targetHeight = output.height;
|
|
15
|
+
const sourceWidth = input.width;
|
|
16
|
+
const sourceHeight = input.height;
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
const target_data = output.data;
|
|
20
|
+
|
|
21
|
+
if (sourceWidth === targetWidth && sourceHeight === targetHeight) {
|
|
22
|
+
// exact size match, nothing to do
|
|
23
|
+
target_data.set(input.data);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const targetRowSize = targetItemSize * targetWidth;
|
|
28
|
+
|
|
29
|
+
const source_scale_x = sourceWidth / targetWidth;
|
|
30
|
+
const source_scale_y = sourceHeight / targetHeight;
|
|
31
|
+
|
|
32
|
+
for (let y = 0; y < targetHeight; y++) {
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
const sample_y = y * source_scale_y;
|
|
36
|
+
const target_row_address = y * targetRowSize;
|
|
37
|
+
|
|
38
|
+
for (let x = 0; x < targetWidth; x++) {
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
const target_offset = target_row_address + x * targetItemSize;
|
|
42
|
+
|
|
43
|
+
input.sampleBilinear(x * source_scale_x, sample_y, target_data, target_offset);
|
|
44
|
+
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -36,8 +36,8 @@ export class CellFilterReadGridLayer extends CellFilter {
|
|
|
36
36
|
// cache required values
|
|
37
37
|
this.__sampler = this.__layer.sampler;
|
|
38
38
|
|
|
39
|
-
this.__u_scale =
|
|
40
|
-
this.__v_scale =
|
|
39
|
+
this.__u_scale = this.__sampler.width / grid.width;
|
|
40
|
+
this.__v_scale = this.__sampler.height / grid.height;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { CellFilterUnaryOperation } from "../../core/CellFilterUnaryOperation.js";
|
|
2
|
+
import { clamp } from "../../../../core/math/clamp.js";
|
|
3
|
+
import { assert } from "../../../../core/assert.js";
|
|
4
|
+
|
|
5
|
+
export class CellFilterSaturate extends CellFilterUnaryOperation {
|
|
6
|
+
operation(v) {
|
|
7
|
+
return clamp(v, 0, 1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @param {CellFilter} v
|
|
13
|
+
* @return {CellFilterUnaryOperation}
|
|
14
|
+
*/
|
|
15
|
+
static from(v) {
|
|
16
|
+
assert.equal(v.isCellFilter, true, "v.isCellFilter !== true");
|
|
17
|
+
|
|
18
|
+
const r = new CellFilterSaturate();
|
|
19
|
+
|
|
20
|
+
r.source = v;
|
|
21
|
+
|
|
22
|
+
return r;
|
|
23
|
+
}
|
|
24
|
+
}
|
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.
|
|
8
|
+
"version": "2.34.0",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|
|
@@ -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);
|