From cab52d489feb323fa70dda626bf9b267718ef8d6 Mon Sep 17 00:00:00 2001 From: HelperWesley <72082749+HelperWesley@users.noreply.github.com> Date: Wed, 28 Oct 2026 14:27:04 -0230 Subject: [PATCH 1/4] Adding terrain to 3D starters Adding the terrain object to the appropriate 3D starters. Also updating the starting wall texture, because it was misaligned by a couple of pixels. --- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-3D-platformer.json | 7975 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-3d-car-racing.json | 8112 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-3d-driving.json | 8029 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-3d-grand-theft-auto.json | 7981 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-3d-tank/assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-3d-tank/starting-3d-tank.json | 8372 ++++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-first-person-farming.json | 7979 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-first-person-horror.json | 7978 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes ...starting-first-person-shooter-enemies.json | 8262 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-first-person-shooter-horror.json | 7990 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-first-person-shooter.json | 7980 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes ...arting-first-person-survival-crafting.json | 7988 +++++++++++++++- .../assets/StartingWall.png | Bin 2757 -> 2756 bytes .../starting-first-person.json | 7984 +++++++++++++++- 29 files changed, 94918 insertions(+), 1712 deletions(-) diff --git a/examples/starting-3D-platformer/assets/StartingWall.png b/examples/starting-3D-platformer/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-3d-camera-monitoring/assets/StartingWall.png b/examples/starting-3d-camera-monitoring/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vBqdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-3d-driving/assets/StartingWall.png b/examples/starting-3d-driving/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-3d-endless-runner/assets/StartingWall.png b/examples/starting-3d-endless-runner/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vBqdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vBqdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-3d-rts-unit-selection/assets/StartingWall.png b/examples/starting-3d-rts-unit-selection/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vBqdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-3d-top-down-rpg/assets/StartingWall.png b/examples/starting-3d-top-down-rpg/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vBqdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-first-person-horror/assets/StartingWall.png b/examples/starting-first-person-horror/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-first-person-shooter-enemies/assets/StartingWall.png b/examples/starting-first-person-shooter-enemies/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", @@ -13528,12 +13482,68 @@ "objectGroups": [] } ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onFirstSceneLoaded" + }, + { + "functionName": "onScenePostEvents" + }, + { + "functionName": "RequestPointerLock" + }, + { + "functionName": "ExitPointerLock" + }, + { + "functionName": "isPointerLocked" + }, + { + "functionName": "isPointerActuallyLocked" + }, + { + "functionName": "isEmulatingPointerLock" + }, + { + "functionName": "IsMoving" + }, + { + "functionName": "MovementX" + }, + { + "functionName": "SetMovementX" + }, + { + "functionName": "MovementY" + }, + { + "functionName": "SetMovementY" + }, + { + "functionName": "TouchX" + }, + { + "functionName": "TouchY" + }, + { + "functionName": "TouchSpeedFactor" + }, + { + "functionName": "SetTouchSpeedFactor" + } + ] + }, "eventsBasedBehaviors": [ { "description": "Control camera rotations with a mouse.", "fullName": "First person camera mouse mapper", + "helpPath": "", + "iconUrl": "", "name": "FirstPersonPointerMapper", "objectType": "", + "previewIconUrl": "", "eventsFunctions": [ { "fullName": "", @@ -13808,6 +13818,7 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "HorizontalSpeed", + "group": "First person camera mouse mapper configuration", "name": "SetHorizontalSpeed", "sentence": "", "events": [ @@ -13888,6 +13899,7 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalSpeed", + "group": "First person camera mouse mapper configuration", "name": "SetVerticalSpeed", "sentence": "", "events": [ @@ -13968,6 +13980,7 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMin", + "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMin", "sentence": "", "events": [ @@ -14048,6 +14061,7 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMax", + "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMax", "sentence": "", "events": [ @@ -14128,6 +14142,7 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "OffsetZ", + "group": "First person camera mouse mapper configuration", "name": "SetOffsetZ", "sentence": "", "events": [ @@ -14164,6 +14179,57 @@ "objectGroups": [] } ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "doStepPreEvents" + }, + { + "folderName": "Layers and cameras", + "children": [ + { + "functionName": "LookFromObjectEyes" + } + ] + }, + { + "folderName": "First person camera mouse mapper configuration", + "children": [ + { + "functionName": "HorizontalSpeed" + }, + { + "functionName": "SetHorizontalSpeed" + }, + { + "functionName": "VerticalSpeed" + }, + { + "functionName": "SetVerticalSpeed" + }, + { + "functionName": "VerticalAngleMin" + }, + { + "functionName": "SetVerticalAngleMin" + }, + { + "functionName": "VerticalAngleMax" + }, + { + "functionName": "SetVerticalAngleMax" + }, + { + "functionName": "OffsetZ" + }, + { + "functionName": "SetOffsetZ" + } + ] + } + ] + }, "propertyDescriptors": [ { "value": "", @@ -14217,7 +14283,32 @@ "name": "ShouldLock" } ], - "sharedPropertyDescriptors": [] + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "propertyName": "Object3D" + }, + { + "propertyName": "HorizontalSpeed" + }, + { + "propertyName": "VerticalSpeed" + }, + { + "propertyName": "VerticalAngleMin" + }, + { + "propertyName": "VerticalAngleMax" + }, + { + "propertyName": "OffsetZ" + }, + { + "propertyName": "ShouldLock" + } + ] + } } ], "eventsBasedObjects": [] @@ -40454,9 +40545,9 @@ "type": "Number", "unit": "PixelSpeed", "label": "Start min speed", + "description": "Initial speed of the particles, in the emission direction (the local Z axis of the emitter).", "group": "Speed", - "name": "StartSpeedMin", - "description": "Initial speed of the particles, in the emission direction (the local Z axis of the emitter)." + "name": "StartSpeedMin" }, { "value": "100", @@ -40485,25 +40576,25 @@ "type": "Number", "unit": "Second", "label": "Emission duration", - "name": "Duration", - "description": "0 emits forever." + "description": "0 emits forever.", + "name": "Duration" }, { "value": "", "type": "Boolean", "label": "Particles move with the emitter", + "description": "When checked, the particles already emitted follow the emitter when it moves or rotates. Leave it unchecked for rain, snow or smoke that must stay where it was emitted while the emitter follows the camera or a character.", "group": "Speed", - "name": "AreParticlesRelative", - "description": "When checked, the particles already emitted follow the emitter when it moves or rotates. Leave it unchecked for rain, snow or smoke that must stay where it was emitted while the emitter follows the camera or a character." + "name": "AreParticlesRelative" }, { "value": "30", "type": "Number", "unit": "DegreeAngle", "label": "Spray cone angle", + "description": "Spread of the particles around the emission direction, which is the local Z axis of the emitter (upward by default, rotate the instance to aim it). 0 or more than 180 emits in every direction, unless an emission zone radius is set: then 0 emits straight.", "group": "Position", - "name": "SpayConeAngle", - "description": "Spread of the particles around the emission direction, which is the local Z axis of the emitter (upward by default, rotate the instance to aim it). 0 or more than 180 emits in every direction, unless an emission zone radius is set: then 0 emits straight." + "name": "SpayConeAngle" }, { "value": "0", @@ -40518,6 +40609,7 @@ "value": "Additive", "type": "Choice", "label": "Blending", + "description": "Additive makes particles glow (fire, magic, energy). Use Normal for rain, snow, smoke or dust. Only applied when the object is created.", "group": "Color", "choices": [ { @@ -40541,13 +40633,13 @@ "value": "None" } ], - "name": "Blending", - "description": "Additive makes particles glow (fire, magic, energy). Use Normal for rain, snow, smoke or dust. Only applied when the object is created." + "name": "Blending" }, { "value": "Y-", "type": "Choice", "label": "Gravity top", + "description": "Z+: gravity pulls particles down along the Z axis (the usual choice in 3D games). Y-: gravity pulls particles toward Y+.", "group": "Speed", "choices": [ { @@ -40559,24 +40651,23 @@ "value": "Z+" } ], - "name": "GravityTop", - "description": "Z+: gravity pulls particles down along the Z axis (the usual choice in 3D games). Y-: gravity pulls particles toward Y+." + "name": "GravityTop" }, { "value": "0", "type": "Number", "unit": "PixelAcceleration", "label": "Gravity", + "description": "Acceleration pulling the particles in the direction given by the gravity top. 0 disables gravity.", "group": "Speed", - "name": "Gravity", - "description": "Acceleration pulling the particles in the direction given by the gravity top. 0 disables gravity." + "name": "Gravity" }, { "value": "true", "type": "Boolean", "label": "Delete when emission ends", - "name": "ShouldAutodestruct", - "description": "Delete the object once the emission duration is over and every particle disappeared. Uncheck it and set the emission duration to 0 for a continuous effect like fire, rain or snow." + "description": "Delete the object once the emission duration is over and every particle disappeared. Uncheck it and set the emission duration to 0 for a continuous effect like fire, rain or snow.", + "name": "ShouldAutodestruct" }, { "value": "Center-center", @@ -40619,25 +40710,26 @@ "type": "Number", "unit": "Dimensionless", "label": "Start min length", + "description": "Number of past positions kept to draw the trail, one per frame: the visible length is this number multiplied by the distance traveled by the particle each frame.", "group": "Trail", "advanced": true, - "name": "TrailStartLengthMin", - "description": "Number of past positions kept to draw the trail, one per frame: the visible length is this number multiplied by the distance traveled by the particle each frame." + "name": "TrailStartLengthMin" }, { "value": "120", "type": "Number", "unit": "Dimensionless", "label": "Start max length", + "description": "Number of past positions kept to draw the trail, one per frame: the visible length is this number multiplied by the distance traveled by the particle each frame.", "group": "Trail", "advanced": true, - "name": "TrailStartLengthMax", - "description": "Number of past positions kept to draw the trail, one per frame: the visible length is this number multiplied by the distance traveled by the particle each frame." + "name": "TrailStartLengthMax" }, { "value": "Billboard", "type": "Choice", "label": "Render mode", + "description": "\"Image facing the camera\" draws each particle as an image. \"Image following a trail\" stretches the image along the path of each particle (sparks, rain streaks).", "choices": [ { "label": "Image facing the camera", @@ -40649,8 +40741,7 @@ } ], "advanced": true, - "name": "RenderMode", - "description": "\"Image facing the camera\" draws each particle as an image. \"Image following a trail\" stretches the image along the path of each particle (sparks, rain streaks)." + "name": "RenderMode" }, { "value": "", @@ -40786,7 +40877,7804 @@ "propertyName": "ParentOrigin" } ] - } + }, + "variants": [] + } + ] + }, + { + "author": "", + "category": "General", + "dimension": "3D", + "extensionNamespace": "", + "fullName": "3D terrain", + "gdevelopVersion": ">=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] } ] } diff --git a/examples/starting-first-person-shooter-horror/assets/StartingWall.png b/examples/starting-first-person-shooter-horror/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-first-person-shooter/assets/StartingWall.png b/examples/starting-first-person-shooter/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-first-person-survival-crafting/assets/StartingWall.png b/examples/starting-first-person-survival-crafting/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] diff --git a/examples/starting-first-person/assets/StartingWall.png b/examples/starting-first-person/assets/StartingWall.png index b3a0978879cf1a33780b0116e5508f41c4960bcb..06278d6e58cded98a3d32d6508d5f429c83ccdc8 100644 GIT binary patch delta 440 zcmX>qdPHCl_Ux97oA)!bF|x2MP-Z|8p1hxVmeCH73v9X1FSgW8;3$ogyL!JX z>*$hWi9TzqtyQ(`oW5{J-pR+c^J6%eK7MMyux88JczybQ2{0%~0u?DRFfs@W;9{y>q7D+33idL3%_@9`HNn< z2uBDu7m}`vxX4Ghi*#KA4Sfuwsg6)4Ll0+I1{mh4&cR}7?q8|M3c1~vnGUTwUG=&y zO-Z2g+D=9m1`ju2X$MPgmnHsjurM@O?f^=F3OJZJmf-m@@%oEHpKr_+69|jF7X95= zxbXyL={LhIGkU*W{g)k*ClbDF+%l8njM?iuK>JjbfhFi*&P#Z`jw57n2!m=9STaKk zPaMJoY65!c!sBo}E+kzS9>b7pWHfJ+p^Nba2g7Kp!<85b1SneY<0?ogPT{1dACOb< z=sFNTb=%kM6vB=5.5.222", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", + "version": "0.1.0", + "description": [ + "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", + "", + "- **Sculpt and paint in the scene editor**: select a terrain to show the tools (raise, lower, smooth, flatten and paint 4 layers).", + "- **Start from a relief** (hills, mountains, island) or **from a heightmap image**.", + "- **Steep slopes automatically show rock** (or any layer).", + "- **Natural borders between layers**: stones and tufts of a texture cover the gaps of the other where layers meet (height blending), and the repetition of textures is made less visible (texture variation).", + "- **Physics**: add the **3D physics** behavior to the terrain. Characters and objects collide with the ground exactly. The terrain is always static.", + "- **Pathfinding**: add the **floor/obstacle for pathfinding (navmesh based)** behavior to the terrain, so that characters with the navmesh pathfinding behavior walk on its hills and around its cliffs (in recent GDevelop versions).", + "- **Shape it with the Edits property**: a list of raise, flatten, smooth and paint strokes written in JSON, shown in the scene editor. It's readable and can be changed by hand or by an AI agent, like the relief, the heightmap and the other properties. Actions only change the terrain during the game.", + "- **Change it during the game** with actions (raise, lower, flatten, smooth, paint, along a line for paths and rivers) and read the ground height, slope or layer with expressions.", + "- **Grass**: add a **terrain grass** object over the terrain. Thousands of blades sway in the wind, grow where a layer (like grass) is painted and where the ground is not too steep, and are pushed aside by characters. Sculpt or paint the terrain and the grass follows.", + "- **Forests, rocks and bushes**: add a **scattered models** object over the terrain. It places hundreds or thousands of copies of a 3D model (trees, rocks, bushes, flowers...) on the ground and draws them all at once, which is much faster than an object for each. Copies grow where a layer is painted, away from steep slopes, and follow the ground when it's sculpted. Add or erase them with the brushes of the scene editor or with the Edits property, give trees trunk collisions, and cut them down with actions. Ready-made forests, rocks and bushes are in the asset store.", + "- **Tunnels and caves**: make holes in the ground (and fill them again) with the brushes, the Edits property or actions, and put a 3D model of the tunnel or the cave (with a mesh collision shape) under the ground. Nothing is drawn in holes, and characters, cars and rays go through them.", + "- **Made for large worlds**: the terrain is split in chunks that are hidden when off-screen and simplified when far away, and collisions are updated only where the ground changes." + ], + "origin": { + "identifier": "Terrain3D", + "name": "gdevelop-extension-store" + }, + "tags": [ + "3d", + "terrain", + "ground", + "heightmap", + "landscape", + "open world", + "grass", + "foliage", + "forest", + "trees", + "tunnel", + "cave" + ], + "authorIds": [], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Define helper classes JavaScript code.", + "fullName": "Define helper classes", + "functionType": "Action", + "name": "DefineHelperClasses", + "private": true, + "sentence": "Define helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrain3DExtension) {", + " return;", + "}", + "", + "// Tested by the gameplay tests of the \"3D island terrain\" example (GDevelop-examples repository).", + "", + "const groundsByScene = new WeakMap();", + "/**", + " * The grounds of a scene (the terrains), followed by the terrain grass.", + " *", + " * A ground has: `getVersion()` (changing when the ground changes),", + " * `containsPoint(x, y)`, `getHeightAt(x, y)` (Z position of the ground),", + " * `getSlopeAt(x, y)` (in degrees), `getLayerWeightAt(x, y, layer)` (how", + " * much a painted layer, from 1 to 4, is there, from 0 to 1) and optionally", + " * `getTintAt(x, y)` (the painted tint, as red, green and blue from 0 to 255).", + " * @param {gdjs.RuntimeScene} runtimeScene", + " * @returns {Set}", + " */", + "const getGrounds = (runtimeScene) => {", + " let grounds = groundsByScene.get(runtimeScene);", + " if (!grounds) {", + " grounds = new Set();", + " groundsByScene.set(runtimeScene, grounds);", + " }", + " return grounds;", + "};", + "", + "/**", + " * @param {number} seed", + " * @returns {() => number} Random numbers between 0 (included) and 1 (excluded), the same for the same seed.", + " */", + "const createRandom = (seed) => {", + " let state = seed >>> 0 || 1;", + " return () => {", + " state ^= state << 13;", + " state ^= state >>> 17;", + " state ^= state << 5;", + " return (state >>> 0) / 4294967296;", + " };", + "};", + "", + "/**", + " * Find the highest ground at a position: grounds can overlap (like an island over a sea floor).", + " * @param {Iterable} grounds", + " * @param {{ground: object | null, z: number}} result Set to the ground (null if there is none) and its Z position.", + " */", + "const findHighestGround = (grounds, x, y, result) => {", + " result.ground = null;", + " for (const ground of grounds) {", + " if (!ground.containsPoint(x, y)) continue;", + " const z = ground.getHeightAt(x, y);", + " if (!result.ground || z > result.z) {", + " result.ground = ground;", + " result.z = z;", + " }", + " }", + " return result;", + "};", + "", + "// The grounds or the objects placed on them can change every frame (while", + "// sculpting or moving them in the editor): things are placed again at most this often.", + "const PLACEMENT_DELAY = 0.3;", + "", + "/**", + " * Tells when things placed on the grounds of a scene (grass blades, scattered", + " * models) must be placed again: after the grounds or the given properties", + " * changed, at most every `PLACEMENT_DELAY` seconds.", + " */", + "class GroundPlacement {", + " /** @param {gdjs.RuntimeScene} runtimeScene */", + " constructor(runtimeScene) {", + " this.grounds = getGrounds(runtimeScene);", + " this.placedFrom = '';", + " this.timeSincePlacement = 0;", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {string} propertiesKey Changes when the things must be placed again.", + " */", + " shouldPlaceAgain(elapsedSeconds, propertiesKey) {", + " this.timeSincePlacement += elapsedSeconds;", + " if (this.placedFrom && this.timeSincePlacement < PLACEMENT_DELAY) return false;", + " let placementKey = propertiesKey;", + " for (const ground of this.grounds) placementKey += '|' + ground.getVersion();", + " if (placementKey === this.placedFrom) return false;", + " this.placedFrom = placementKey;", + " this.timeSincePlacement = 0;", + " return true;", + " }", + "", + " placeAgain() {", + " this.placedFrom = '';", + " }", + "}", + "", + "/**", + " * Replace parts of the shader code of a Three.js material, with an error if", + " * a part is missing (for example after an update of Three.js).", + " * @param {string} shaderCode", + " * @param {Array<[string, string]>} replacements The searched code and its replacement.", + " * @param {string} materialName", + " */", + "const patchShaderCode = (shaderCode, replacements, materialName) => {", + " for (const [searchedCode, newCode] of replacements) {", + " if (!shaderCode.includes(searchedCode)) {", + " console.error(`${materialName}: \"${searchedCode}\" was not found in the shader, which won't look as expected.`);", + " }", + " shaderCode = shaderCode.replace(searchedCode, newCode);", + " }", + " return shaderCode;", + "};", + "", + "// Size of the object inner area. Instances are scaled from it, so these only", + "// define the default size of a new terrain.", + "const AREA_SIZE = 4096;", + "const AREA_DEPTH = 600;", + "", + "// Terrains have at most 8 x 8 chunks (so at most 64 draw calls), of at least", + "// 32 x 32 cells.", + "const MIN_CHUNK_CELLS = 32;", + "const MAX_CHUNKS_PER_SIDE = 8;", + "/** @param {number} resolution */", + "const getChunkCells = (resolution) => Math.max(MIN_CHUNK_CELLS, resolution / MAX_CHUNKS_PER_SIDE);", + "// Grid steps of each level of detail, and the distance (in chunk sizes)", + "// from which each one is used.", + "const LOD_STEPS = [1, 2, 4];", + "const LOD_DISTANCES = [0, 3, 6];", + "", + "const LAYER_COUNT = 4;", + "const RESOLUTIONS = [64, 128, 256, 512, 1024];", + "const DEFAULT_RESOLUTION = 256;", + "// Each undo step is a copy of the data: fewer are kept for big terrains.", + "const UNDO_STEPS_SAMPLES = 20 * 257 * 257;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "const clampInteger = (value, min, max) =>", + " value < min ? min : value > max ? max : Math.floor(value);", + "", + "/**", + " * A rectangle of grid samples, inclusive. Empty when `minI > maxI`.", + " */", + "class SampleRectangle {", + " constructor() {", + " this.clear();", + " }", + "", + " clear() {", + " this.minI = Number.MAX_SAFE_INTEGER;", + " this.minJ = Number.MAX_SAFE_INTEGER;", + " this.maxI = -1;", + " this.maxJ = -1;", + " }", + "", + " isEmpty() {", + " return this.minI > this.maxI;", + " }", + "", + " /** @param {SampleRectangle} other */", + " add(other) {", + " if (other.isEmpty()) return;", + " this.minI = Math.min(this.minI, other.minI);", + " this.minJ = Math.min(this.minJ, other.minJ);", + " this.maxI = Math.max(this.maxI, other.maxI);", + " this.maxJ = Math.max(this.maxJ, other.maxJ);", + " }", + "", + " set(minI, minJ, maxI, maxJ) {", + " this.minI = minI;", + " this.minJ = minJ;", + " this.maxI = maxI;", + " this.maxJ = maxJ;", + " return this;", + " }", + "}", + "", + "/**", + " * The heights (between 0 and 1) and the painted layers weights of a square", + " * grid of `size * size` samples.", + " */", + "class TerrainData {", + " /** @param {number} resolution The number of cells on each side. */", + " constructor(resolution) {", + " this.resolution = resolution;", + " this.size = resolution + 1;", + " this.heights = new Float32Array(this.size * this.size);", + " /** 4 weights (0-255) per sample, one for each layer. */", + " this.splat = new Uint8Array(this.size * this.size * LAYER_COUNT);", + " this.fillLayer(0);", + " /**", + " * 4 bytes per sample: a tint multiplying the layers (red, green and", + " * blue, white for none) and the wetness (0 for dry).", + " */", + " this.colors = new Uint8Array(this.size * this.size * 4);", + " this.clearColors();", + " }", + "", + " clearColors() {", + " this.colors.fill(255);", + " for (let index = 3; index < this.colors.length; index += 4) {", + " this.colors[index] = 0;", + " }", + " }", + "", + " /** @param {number} layer */", + " fillLayer(layer) {", + " this.splat.fill(0);", + " for (let index = layer; index < this.splat.length; index += LAYER_COUNT) {", + " this.splat[index] = 255;", + " }", + " }", + "", + " getHeight(i, j) {", + " const last = this.resolution;", + " const clampedI = i < 0 ? 0 : i > last ? last : i;", + " const clampedJ = j < 0 ? 0 : j > last ? last : j;", + " return this.heights[clampedJ * this.size + clampedI];", + " }", + "", + " /**", + " * @param {number} gridX", + " * @param {number} gridY", + " * @returns {number} The height interpolated on the triangles that are drawn.", + " */", + " sampleHeight(gridX, gridY) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const topRight = this.getHeight(i + 1, j);", + " const bottomLeft = this.getHeight(i, j + 1);", + " if (fx + fy <= 1) {", + " const topLeft = this.getHeight(i, j);", + " return topLeft + fx * (topRight - topLeft) + fy * (bottomLeft - topLeft);", + " }", + " const bottomRight = this.getHeight(i + 1, j + 1);", + " return (", + " bottomRight +", + " (1 - fx) * (bottomLeft - bottomRight) +", + " (1 - fy) * (topRight - bottomRight)", + " );", + " }", + "", + " /** @returns {number} The weight (0-1) of a layer, interpolated between samples. */", + " sampleLayerWeight(gridX, gridY, layer) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const weight = (i, j) => this.splat[(j * this.size + i) * LAYER_COUNT + layer];", + " const top = weight(i, j) + fx * (weight(i + 1, j) - weight(i, j));", + " const bottom = weight(i, j + 1) + fx * (weight(i + 1, j + 1) - weight(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} channel 0, 1 and 2 for the tint, 3 for the wetness.", + " * @returns {number} The channel (0-1), interpolated between samples.", + " */", + " sampleColor(gridX, gridY, channel) {", + " const x = Math.min(Math.max(gridX, 0), this.resolution);", + " const y = Math.min(Math.max(gridY, 0), this.resolution);", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.colors[(j * this.size + i) * 4 + channel];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * @param {number} index The index of a sample.", + " * @returns {boolean} true if no layer is painted on the sample: it's a hole.", + " */", + " isHole(index) {", + " const offset = index * LAYER_COUNT;", + " return (this.splat[offset] | this.splat[offset + 1] | this.splat[offset + 2] | this.splat[offset + 3]) === 0;", + " }", + "", + " /**", + " * @returns {number} The sum of the layer weights (0-1), interpolated between samples: there is a", + " * hole where it's under 0.5, like what is drawn.", + " */", + " sampleSolidity(gridX, gridY) {", + " let solidity = 0;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) solidity += this.sampleLayerWeight(gridX, gridY, layer);", + " return solidity;", + " }", + "", + " /** @returns {number} The index (from 0) of the layer painted the most. */", + " getDominantLayer(gridX, gridY) {", + " const i = clampInteger(Math.round(gridX), 0, this.resolution);", + " const j = clampInteger(Math.round(gridY), 0, this.resolution);", + " const offset = (j * this.size + i) * LAYER_COUNT;", + " let dominantLayer = 0;", + " for (let layer = 1; layer < LAYER_COUNT; layer++) {", + " if (this.splat[offset + layer] > this.splat[offset + dominantLayer]) {", + " dominantLayer = layer;", + " }", + " }", + " return dominantLayer;", + " }", + "", + " /** @param {TerrainData} other */", + " copyFrom(other) {", + " this.heights.set(other.heights);", + " this.splat.set(other.splat);", + " this.colors.set(other.colors);", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} A copy of this data with another resolution.", + " */", + " resampled(resolution) {", + " const data = new TerrainData(resolution);", + " const ratio = this.resolution / resolution;", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " data.heights[index] = this.sampleHeight(i * ratio, j * ratio);", + " const sourceOffset =", + " (Math.round(j * ratio) * this.size + Math.round(i * ratio)) * LAYER_COUNT;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " data.splat[index * LAYER_COUNT + layer] = this.splat[sourceOffset + layer];", + " }", + " for (let channel = 0; channel < 4; channel++) {", + " data.colors[index * 4 + channel] = this.colors[sourceOffset + channel];", + " }", + " }", + " }", + " return data;", + " }", + "}", + "", + "/**", + " * Brushes change the samples around a segment, with an effect going smoothly", + " * from full on the segment to none at `radius`. A point is a segment of", + " * length 0. Positions are in scene units relative to the terrain origin.", + " */", + "const brushes = {", + " /**", + " * @param {TerrainData} data", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {(sampleIndex: number, weight: number, t: number) => void} apply Called with the weight of", + " * the brush and the position (from 0 to 1) of the nearest point of the segment.", + " * @param {SampleRectangle} changedSamples", + " */", + " forEachSample(data, stroke, apply, changedSamples) {", + " const { cellWidth, cellHeight, ax, ay, bx, by, radius } = stroke;", + " const last = data.resolution;", + " const minI = clampInteger(Math.floor((Math.min(ax, bx) - radius) / cellWidth), 0, last);", + " const maxI = clampInteger(Math.ceil((Math.max(ax, bx) + radius) / cellWidth), 0, last);", + " const minJ = clampInteger(Math.floor((Math.min(ay, by) - radius) / cellHeight), 0, last);", + " const maxJ = clampInteger(Math.ceil((Math.max(ay, by) + radius) / cellHeight), 0, last);", + " changedSamples.set(minI, minJ, maxI, maxJ);", + " if (radius <= 0) return;", + "", + " const abX = bx - ax;", + " const abY = by - ay;", + " const abLengthSquared = abX * abX + abY * abY;", + " const radiusSquared = radius * radius;", + " for (let j = minJ; j <= maxJ; j++) {", + " const y = j * cellHeight;", + " for (let i = minI; i <= maxI; i++) {", + " const x = i * cellWidth;", + " const t =", + " abLengthSquared > 0", + " ? clamp01(((x - ax) * abX + (y - ay) * abY) / abLengthSquared)", + " : 0;", + " const dx = x - (ax + t * abX);", + " const dy = y - (ay + t * abY);", + " const distanceSquared = dx * dx + dy * dy;", + " if (distanceSquared >= radiusSquared) continue;", + " const falloff = 1 - distanceSquared / radiusSquared;", + " apply(j * data.size + i, falloff * falloff, t);", + " }", + " }", + " },", + "", + " raise(data, stroke, amount, changedSamples) {", + " const { heights } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " heights[index] = clamp01(heights[index] + amount * weight);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * @param {number} targetHeight", + " * @param {number} [endTargetHeight] The target at the end of the segment, for a slope (like a road", + " * going up). The same target as at its start by default.", + " */", + " flatten(data, stroke, targetHeight, strength, changedSamples, endTargetHeight = targetHeight) {", + " const { heights } = data;", + " const startTarget = clamp01(targetHeight);", + " const endTarget = clamp01(endTargetHeight);", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight, t) => {", + " const target = startTarget + (endTarget - startTarget) * t;", + " heights[index] += (target - heights[index]) * clamp01(weight * strength);", + " },", + " changedSamples", + " );", + " },", + "", + " smooth(data, stroke, strength, changedSamples) {", + " const { heights, size } = data;", + " const changes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const i = index % size;", + " const j = (index - i) / size;", + " let sum = 0;", + " for (let dj = -1; dj <= 1; dj++) {", + " for (let di = -1; di <= 1; di++) {", + " sum += data.getHeight(i + di, j + dj);", + " }", + " }", + " changes.push(index, heights[index] + (sum / 9 - heights[index]) * clamp01(weight * strength));", + " },", + " changedSamples", + " );", + " // Written after all averages are computed, so that the result", + " // doesn't depend on the order in which samples are visited.", + " for (let index = 0; index < changes.length; index += 2) {", + " heights[changes[index]] = changes[index + 1];", + " }", + " },", + "", + " paint(data, stroke, layer, strength, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " const offset = index * LAYER_COUNT;", + " for (let otherLayer = 0; otherLayer < LAYER_COUNT; otherLayer++) {", + " const target = otherLayer === layer ? 255 : 0;", + " const value = splat[offset + otherLayer];", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - value) * amount;", + " splat[offset + otherLayer] = value + (change > 0 ? Math.ceil(change) : Math.floor(change));", + " }", + " },", + " changedSamples", + " );", + " },", + "", + " /** Remove all the layers, making a hole (`fill` or painting a layer fills it again). */", + " hole(data, stroke, changedSamples) {", + " const { splat } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " splat.fill(0, index * LAYER_COUNT, (index + 1) * LAYER_COUNT);", + " },", + " changedSamples", + " );", + " },", + "", + " /**", + " * Fill the holes in the radius with the layers of the ground around them:", + " * each pass fills the holes next to the ground with the average of their", + " * neighbors, from the edges of the holes inward.", + " */", + " fill(data, stroke, changedSamples) {", + " const { splat, size, resolution } = data;", + " /** @type {number[]} */", + " let holes = [];", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index) => {", + " if (data.isHole(index)) holes.push(index);", + " },", + " changedSamples", + " );", + " const filledWeights = new Float32Array(holes.length * LAYER_COUNT);", + " while (holes.length > 0) {", + " /** @type {number[]} */", + " const remainingHoles = [];", + " /** @type {number[]} */", + " const filledHoles = [];", + " for (const index of holes) {", + " const i = index % size;", + " const j = (index - i) / size;", + " const weights = filledWeights.subarray(filledHoles.length * LAYER_COUNT, (filledHoles.length + 1) * LAYER_COUNT);", + " weights.fill(0);", + " for (let neighborJ = Math.max(j - 1, 0); neighborJ <= Math.min(j + 1, resolution); neighborJ++) {", + " for (let neighborI = Math.max(i - 1, 0); neighborI <= Math.min(i + 1, resolution); neighborI++) {", + " const neighbor = neighborJ * size + neighborI;", + " if (data.isHole(neighbor)) continue;", + " for (let layer = 0; layer < LAYER_COUNT; layer++) weights[layer] += splat[neighbor * LAYER_COUNT + layer];", + " }", + " }", + " if (weights[0] + weights[1] + weights[2] + weights[3] > 0) filledHoles.push(index);", + " else remainingHoles.push(index);", + " }", + " if (filledHoles.length === 0) {", + " // No ground around (a hole bigger than the brush): the first layer is used.", + " for (const index of remainingHoles) splat[index * LAYER_COUNT] = 255;", + " break;", + " }", + " // Filled after the pass, so that the holes are filled from the edges inward.", + " filledHoles.forEach((index, filledIndex) => {", + " const weights = filledWeights.subarray(filledIndex * LAYER_COUNT, (filledIndex + 1) * LAYER_COUNT);", + " const total = weights[0] + weights[1] + weights[2] + weights[3];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " splat[index * LAYER_COUNT + layer] = Math.round((weights[layer] / total) * 255);", + " }", + " });", + " holes = remainingHoles;", + " }", + " },", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(data, stroke, color, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 0, color, strength, changedSamples);", + " },", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(data, stroke, wetness, strength, changedSamples) {", + " brushes.paintColors(data, stroke, 3, [Math.round(clamp01(wetness) * 255)], strength, changedSamples);", + " },", + "", + " /**", + " * Bring channels of the colors (see `TerrainData.colors`) towards targets.", + " * @param {number} firstChannel", + " * @param {number[]} targets From 0 to 255, for the channels from the first one.", + " */", + " paintColors(data, stroke, firstChannel, targets, strength, changedSamples) {", + " const { colors } = data;", + " brushes.forEachSample(", + " data,", + " stroke,", + " (index, weight) => {", + " const amount = clamp01(weight * strength);", + " for (let channel = 0; channel < targets.length; channel++) {", + " const offset = index * 4 + firstChannel + channel;", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (targets[channel] - colors[offset]) * amount;", + " colors[offset] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " }", + " },", + " changedSamples", + " );", + " },", + "};", + "", + "const relief = (() => {", + " const hash = (x, y, seed) => {", + " let h = Math.imul(x, 374761393) + Math.imul(y, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return ((h ^ (h >>> 16)) >>> 0) / 4294967296;", + " };", + " const valueNoise = (x, y, seed) => {", + " const x0 = Math.floor(x);", + " const y0 = Math.floor(y);", + " const fx = x - x0;", + " const fy = y - y0;", + " const sx = fx * fx * (3 - 2 * fx);", + " const sy = fy * fy * (3 - 2 * fy);", + " const top = hash(x0, y0, seed) + sx * (hash(x0 + 1, y0, seed) - hash(x0, y0, seed));", + " const bottom =", + " hash(x0, y0 + 1, seed) + sx * (hash(x0 + 1, y0 + 1, seed) - hash(x0, y0 + 1, seed));", + " return top + sy * (bottom - top);", + " };", + " /** Fractal noise between 0 and 1. */", + " const fractalNoise = (x, y, seed) => {", + " let value = 0;", + " let amplitude = 0.5;", + " let frequency = 1;", + " for (let octave = 0; octave < 5; octave++) {", + " value += amplitude * valueNoise(x * frequency, y * frequency, seed + octave);", + " amplitude *= 0.5;", + " frequency *= 2;", + " }", + " return value / 0.96875;", + " };", + " const smoothstep = (edge0, edge1, x) => {", + " const t = clamp01((x - edge0) / (edge1 - edge0));", + " return t * t * (3 - 2 * t);", + " };", + " const reliefHeights = {", + " Flat: () => 0,", + " Hills: (u, v, seed) => 0.05 + 0.5 * Math.pow(fractalNoise(u * 3, v * 3, seed), 2),", + " Mountains: (u, v, seed) => {", + " const ridge = 1 - Math.abs(2 * fractalNoise(u * 2.5, v * 2.5, seed) - 1);", + " return 0.9 * Math.pow(ridge, 2.5);", + " },", + " Island: (u, v, seed) => {", + " const distanceToCenter = 2 * Math.hypot(u - 0.5, v - 0.5);", + " const coast = 0.2 * (fractalNoise(u * 4, v * 4, seed + 7) - 0.5);", + " const land = smoothstep(0.95, 0.55, distanceToCenter + coast);", + " return land * (0.12 + 0.6 * Math.pow(fractalNoise(u * 3, v * 3, seed), 1.5));", + " },", + " };", + " const beachLayer = 3;", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {string} reliefName Flat, Hills, Mountains or Island.", + " * @param {number} seed", + " */", + " generate(data, reliefName, seed) {", + " const getHeight = reliefHeights[reliefName] || reliefHeights.Flat;", + " const integerSeed = Math.floor(seed) | 0;", + " data.fillLayer(0);", + " for (let j = 0; j < data.size; j++) {", + " for (let i = 0; i < data.size; i++) {", + " const index = j * data.size + i;", + " const height = clamp01(", + " getHeight(i / data.resolution, j / data.resolution, integerSeed)", + " );", + " data.heights[index] = height;", + " if (reliefName === 'Island') {", + " const sand = Math.round(255 * smoothstep(0.16, 0.1, height));", + " const offset = index * LAYER_COUNT;", + " data.splat[offset] = 255 - sand;", + " data.splat[offset + beachLayer] = sand;", + " }", + " }", + " }", + " },", + " };", + "})();", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"raise\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2, \"height\": 0.3}]`,", + " * applied on the relief or the heightmap. Positions and radius are fractions", + " * of the terrain size, heights and Z positions fractions of its depth: they", + " * are the same for all instances, whatever their size. They are made to be", + " * read and written by people and by AI agents.", + " */", + "const edits = {", + " /**", + " * @param {TerrainData} data", + " * @param {string} text", + " */", + " apply(data, text) {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of a terrain are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of a terrain must be a JSON list (like [{\"tool\": \"raise\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / data.resolution,", + " cellHeight: 1 / data.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'raise') {", + " brushes.raise(data, stroke, numberOr(edit.height, 0.1), changedSamples);", + " } else if (edit.tool === 'flatten') {", + " const z = numberOr(edit.z, 0);", + " brushes.flatten(data, stroke, z, strength, changedSamples, numberOr(edit.toZ, z));", + " } else if (edit.tool === 'smooth') {", + " // Smoothing the same fraction of the terrain at any resolution.", + " const passes = Math.max(Math.round(((1 + 9 * strength) * data.resolution) / 256), 1);", + " for (let pass = 0; pass < passes; pass++) brushes.smooth(data, stroke, 1, changedSamples);", + " } else if (edit.tool === 'paint') {", + " const layer = clampInteger(numberOr(edit.layer, 1) - 1, 0, LAYER_COUNT - 1);", + " brushes.paint(data, stroke, layer, strength, changedSamples);", + " } else if (edit.tool === 'tint') {", + " const color = gdjs.rgbOrHexToRGBColor(typeof edit.color === 'string' ? edit.color : '255;255;255');", + " brushes.tint(data, stroke, color, strength, changedSamples);", + " } else if (edit.tool === 'wetness') {", + " brushes.wet(data, stroke, numberOr(edit.amount, 1), strength, changedSamples);", + " } else if (edit.tool === 'hole') {", + " brushes.hole(data, stroke, changedSamples);", + " } else if (edit.tool === 'fill') {", + " brushes.fill(data, stroke, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of a terrain: \"' + edit.tool + '\" (use raise, flatten, smooth, paint, tint, wetness, hole or fill).');", + " }", + " }", + " },", + "};", + "", + "/**", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", + " */", + "const getLoadedImage = (game, imageResourceName) => {", + " const imageManager = game.getImageManager();", + " if (typeof imageManager.getImageSource === 'function') return imageManager.getImageSource(imageResourceName);", + " // Older GDevelop versions: a 192 x 192 placeholder is given for images that are not loaded.", + " const texture = imageManager.getPIXITexture(imageResourceName);", + " return texture && texture !== imageManager.getInvalidPIXITexture() ? texture.baseTexture.getDrawableSource() : null;", + "};", + "", + "/**", + " * Loads heights from an image: black is the lowest, white the highest.", + " * Heights have 16 bits of precision when the red channel holds the most", + " * significant byte and the green one the least significant (a gray image", + " * works as expected too).", + " * @param {TerrainData} data", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} imageResourceName", + " * @returns {boolean} true if the image could be read.", + " */", + "const loadHeightsFromImage = (data, game, imageResourceName) => {", + " const source = getLoadedImage(game, imageResourceName);", + " if (!source) return false;", + "", + " const canvas = document.createElement('canvas');", + " canvas.width = source.width;", + " canvas.height = source.height;", + " const context = canvas.getContext('2d', { willReadFrequently: true });", + " if (!context) return false;", + " context.drawImage(source, 0, 0);", + " const pixels = context.getImageData(0, 0, source.width, source.height).data;", + " // Pixels are decoded before being interpolated, to keep the 16 bits.", + " const pixelHeight = (x, y) => {", + " const offset = (y * source.width + x) * 4;", + " return (256 * pixels[offset] + pixels[offset + 1]) / 65535;", + " };", + " for (let j = 0; j < data.size; j++) {", + " const y = (j / data.resolution) * (source.height - 1);", + " const y0 = Math.floor(y);", + " const y1 = Math.min(y0 + 1, source.height - 1);", + " for (let i = 0; i < data.size; i++) {", + " const x = (i / data.resolution) * (source.width - 1);", + " const x0 = Math.floor(x);", + " const x1 = Math.min(x0 + 1, source.width - 1);", + " const top = pixelHeight(x0, y0) + (x - x0) * (pixelHeight(x1, y0) - pixelHeight(x0, y0));", + " const bottom = pixelHeight(x0, y1) + (x - x0) * (pixelHeight(x1, y1) - pixelHeight(x0, y1));", + " data.heights[j * data.size + i] = top + (y - y0) * (bottom - top);", + " }", + " }", + " return true;", + "};", + "", + "/**", + " * Stores the data in a string. Only the differences with the base data (from", + " * the relief or the heightmap) are stored: heights on 16 bits, layer weights", + " * on 8 bits, then (since format 2) the tint and wetness on 8 bits. Each value is predicted from its neighbors and the", + " * prediction errors are written as variable length integers, with runs of", + " * zeros collapsed. Untouched or smoothly changed areas take almost no space.", + " */", + "const codec = (() => {", + " const formatVersion = '2';", + " // Format 1 has no tint and wetness.", + " const readableFormatVersions = ['1', '2'];", + "", + " class ByteWriter {", + " constructor() {", + " this.bytes = new Uint8Array(1024);", + " this.length = 0;", + " }", + " writeVarUint(value) {", + " if (this.length + 5 > this.bytes.length) {", + " const bytes = new Uint8Array(this.bytes.length * 2);", + " bytes.set(this.bytes);", + " this.bytes = bytes;", + " }", + " while (value >= 0x80) {", + " this.bytes[this.length++] = (value & 0x7f) | 0x80;", + " value >>>= 7;", + " }", + " this.bytes[this.length++] = value;", + " }", + " }", + "", + " class ByteReader {", + " /** @param {Uint8Array} bytes */", + " constructor(bytes) {", + " this.bytes = bytes;", + " this.position = 0;", + " }", + " readVarUint() {", + " let value = 0;", + " let shift = 0;", + " let byte;", + " do {", + " if (this.position >= this.bytes.length) throw new Error('Truncated terrain data.');", + " byte = this.bytes[this.position++];", + " value += (byte & 0x7f) * Math.pow(2, shift);", + " shift += 7;", + " } while (byte & 0x80);", + " return value;", + " }", + " }", + "", + " /** Predicts a value from the left, top and top-left ones. */", + " const predict = (values, size, index) => {", + " const i = index % size;", + " if (index < size) return i === 0 ? 0 : values[index - 1];", + " if (i === 0) return values[index - size];", + " return values[index - 1] + values[index - size] - values[index - size - 1];", + " };", + "", + " /**", + " * @param {ByteWriter} writer", + " * @param {Int32Array} values A grid of `size * size` values.", + " */", + " const writeGrid = (writer, values, size) => {", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " const error = values[index] - predict(values, size, index);", + " if (error === 0) {", + " zeroRun++;", + " continue;", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " zeroRun = 0;", + " }", + " // Zigzag: small negative and positive numbers get small codes.", + " writer.writeVarUint(error > 0 ? error * 2 : -error * 2 - 1);", + " }", + " if (zeroRun > 0) {", + " writer.writeVarUint(0);", + " writer.writeVarUint(zeroRun);", + " }", + " };", + "", + " /** @param {ByteReader} reader */", + " const readGrid = (reader, size) => {", + " const values = new Int32Array(size * size);", + " let zeroRun = 0;", + " for (let index = 0; index < values.length; index++) {", + " let error = 0;", + " if (zeroRun > 0) {", + " zeroRun--;", + " } else {", + " const code = reader.readVarUint();", + " if (code === 0) {", + " zeroRun = reader.readVarUint() - 1;", + " } else {", + " error = code % 2 === 0 ? code / 2 : -(code + 1) / 2;", + " }", + " }", + " values[index] = predict(values, size, index) + error;", + " }", + " return values;", + " };", + "", + " const toBase64 = (bytes, length) => {", + " let binary = '';", + " for (let offset = 0; offset < length; offset += 0x8000) {", + " binary += String.fromCharCode.apply(null, bytes.subarray(offset, Math.min(offset + 0x8000, length)));", + " }", + " return btoa(binary);", + " };", + "", + " const fromBase64 = (base64) => {", + " const binary = atob(base64);", + " const bytes = new Uint8Array(binary.length);", + " for (let index = 0; index < binary.length; index++) {", + " bytes[index] = binary.charCodeAt(index);", + " }", + " return bytes;", + " };", + "", + " return {", + " /**", + " * @param {TerrainData} data", + " * @param {TerrainData} baseData The data without changes, with the same resolution.", + " */", + " encode(data, baseData) {", + " const writer = new ByteWriter();", + " const values = new Int32Array(data.heights.length);", + " for (let index = 0; index < values.length; index++) {", + " values[index] = Math.round((data.heights[index] - baseData.heights[index]) * 65535);", + " }", + " writeGrid(writer, values, data.size);", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " values[index] = data.splat[offset] - baseData.splat[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " // Not painted, these grids are zeros: a few bytes each.", + " for (let channel = 0; channel < 4; channel++) {", + " for (let index = 0; index < values.length; index++) {", + " const offset = index * 4 + channel;", + " values[index] = data.colors[offset] - baseData.colors[offset];", + " }", + " writeGrid(writer, values, data.size);", + " }", + " return formatVersion + ';' + data.resolution + ';' + toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * Store grids of integers in a string, like the terrain data. Used by other objects (the scattered models).", + " * @param {Int32Array[]} grids Grids of `size * size` values.", + " * @param {number} size", + " */", + " encodeGrids(grids, size) {", + " const writer = new ByteWriter();", + " for (const grid of grids) writeGrid(writer, grid, size);", + " return toBase64(writer.bytes, writer.length);", + " },", + "", + " /**", + " * @param {string} base64 A string from `encodeGrids`.", + " * @param {number} size", + " * @param {number} count The number of grids.", + " * @returns {Int32Array[]} The grids (an error is thrown if the string is not valid).", + " */", + " decodeGrids(base64, size, count) {", + " const reader = new ByteReader(fromBase64(base64));", + " return Array.from({ length: count }, () => readGrid(reader, size));", + " },", + "", + " /**", + " * @param {string} text", + " * @param {(resolution: number) => TerrainData} createBaseData", + " * @returns {TerrainData | null} null if the text is empty or not valid.", + " */", + " decode(text, createBaseData) {", + " if (!text) return null;", + " const parts = text.split(';');", + " const resolution = parseInt(parts[1], 10);", + " if (readableFormatVersions.indexOf(parts[0]) === -1 || RESOLUTIONS.indexOf(resolution) === -1) {", + " return null;", + " }", + " try {", + " const reader = new ByteReader(fromBase64(parts[2]));", + " const data = createBaseData(resolution);", + " const heightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < heightChanges.length; index++) {", + " data.heights[index] = clamp01(data.heights[index] + heightChanges[index] / 65535);", + " }", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " const weightChanges = readGrid(reader, data.size);", + " for (let index = 0; index < weightChanges.length; index++) {", + " const offset = index * LAYER_COUNT + layer;", + " // The base may have changed since the data was saved.", + " data.splat[offset] = Math.min(Math.max(data.splat[offset] + weightChanges[index], 0), 255);", + " }", + " }", + " if (parts[0] !== '1') {", + " for (let channel = 0; channel < 4; channel++) {", + " const colorChanges = readGrid(reader, data.size);", + " for (let index = 0; index < colorChanges.length; index++) {", + " const offset = index * 4 + channel;", + " data.colors[offset] = Math.min(Math.max(data.colors[offset] + colorChanges[index], 0), 255);", + " }", + " }", + " }", + " return data;", + " } catch (error) {", + " console.error('Terrain data could not be read:', error);", + " return null;", + " }", + " },", + " };", + "})();", + "", + "const lodIndices = new Map();", + "/**", + " * The triangles of a chunk, shared by all chunks of the same size. Chunk", + " * borders have a skirt going down, hiding the gaps between chunks drawn", + " * with different levels of detail.", + " * @param {number} chunkCells", + " * @param {number} step", + " */", + "const getLodIndex = (chunkCells, step) => {", + " const key = chunkCells + ';' + step;", + " const existingIndex = lodIndices.get(key);", + " if (existingIndex) return existingIndex;", + "", + " const sideVertices = chunkCells + 1;", + " const gridVertices = sideVertices * sideVertices;", + " const indices = [];", + " const grid = (i, j) => j * sideVertices + i;", + " for (let j = 0; j < chunkCells; j += step) {", + " for (let i = 0; i < chunkCells; i += step) {", + " const topLeft = grid(i, j);", + " const topRight = grid(i + step, j);", + " const bottomLeft = grid(i, j + step);", + " const bottomRight = grid(i + step, j + step);", + " indices.push(topLeft, topRight, bottomLeft, topRight, bottomRight, bottomLeft);", + " }", + " }", + " const borders = [", + " (k) => grid(k, 0),", + " (k) => grid(k, chunkCells),", + " (k) => grid(0, k),", + " (k) => grid(chunkCells, k),", + " ];", + " borders.forEach((borderVertex, border) => {", + " const skirtVertex = (k) => gridVertices + border * sideVertices + k;", + " for (let k = 0; k < chunkCells; k += step) {", + " const a = borderVertex(k);", + " const b = borderVertex(k + step);", + " const skirtA = skirtVertex(k);", + " const skirtB = skirtVertex(k + step);", + " // Both faces, as a skirt can be seen from either side.", + " indices.push(a, b, skirtB, a, skirtB, skirtA, a, skirtB, b, a, skirtA, skirtB);", + " }", + " });", + " const index = new THREE.BufferAttribute(new Uint16Array(indices), 1);", + " lodIndices.set(key, index);", + " return index;", + "};", + "", + "const vertexShaderDeclarations = `", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "uniform float terrainWorldScale;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "`;", + "const vertexShaderCode = `", + "vTerrainLocalXY = position.xy;", + "vTerrainLocalZ = position.z;", + "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", + "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "`;", + "const fragmentShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "uniform vec3 terrainLayerColors[4];", + "uniform sampler2D terrainLayerMap0;", + "uniform sampler2D terrainLayerMap1;", + "uniform sampler2D terrainLayerMap2;", + "uniform sampler2D terrainLayerMap3;", + "uniform sampler2D terrainLayerNormalMap0;", + "uniform sampler2D terrainLayerNormalMap1;", + "uniform sampler2D terrainLayerNormalMap2;", + "uniform sampler2D terrainLayerNormalMap3;", + "uniform float terrainHasNormalMaps;", + "uniform float terrainNormalMapStrength;", + "uniform float terrainTextureSize;", + "uniform float terrainHeightBlending;", + "uniform float terrainTextureVariation;", + "uniform vec4 terrainCliffLayer;", + "uniform vec2 terrainCliffCosines;", + "uniform vec4 terrainBrush;", + "uniform sampler2D terrainColorMap;", + "uniform vec3 terrainWetShore;", + "varying vec2 vTerrainLocalXY;", + "varying float vTerrainLocalZ;", + "varying vec2 vTerrainWorldXY;", + "varying float vTerrainUp;", + "", + "float terrainHash(vec2 p) {", + " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", + "}", + "// The rotation of the copies of textures used to make repetition less visible.", + "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", + "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", + "vec3 terrainSampleNormal(sampler2D normalMap, vec2 uv, vec2 uv2, float patches) {", + " vec3 bump = texture2D(normalMap, uv).xyz * 2.0 - 1.0;", + " if (patches <= 0.0) return bump;", + " vec3 copyBump = texture2D(normalMap, uv2).xyz * 2.0 - 1.0;", + " // The bumps of the copy are rotated back with the inverse rotation.", + " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", + " return mix(bump, copyBump, patches);", + "}", + "float terrainNoise(vec2 p) {", + " vec2 i = floor(p);", + " vec2 f = fract(p);", + " vec2 u = f * f * (3.0 - 2.0 * f);", + " return mix(", + " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", + " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", + " u.y", + " );", + "}", + "`;", + "// Holes are samples without any painted layer: the interpolated sum of the", + "// weights gives smooth edges. Only compiled for terrains having holes, as", + "// discard makes drawing slower on some GPUs.", + "const holeShaderCode = `", + "#ifdef TERRAIN_HOLES", + "if (dot(texture2D(terrainSplatMap, vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y), vec4(1.0)) < 0.5) discard;", + "#endif", + "`;", + "// For the shadows: the depth of holes is not drawn.", + "const holeDepthShaderDeclarations = `", + "uniform sampler2D terrainSplatMap;", + "uniform vec2 terrainSplatUvScaleAndOffset;", + "varying vec2 vTerrainLocalXY;", + "`;", + "", + "const fragmentShaderCode = holeShaderCode + `", + "// Borders between layers are made irregular and sharper, to look painted.", + "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", + "vec4 terrainJitter = vec4(", + " terrainNoise(terrainNoisePosition),", + " terrainNoise(terrainNoisePosition + 19.1),", + " terrainNoise(terrainNoisePosition + 37.7),", + " terrainNoise(terrainNoisePosition + 53.3)", + ");", + "// Layer weights are in a texture, so that painted details stay the same", + "// whatever the level of detail of the ground.", + "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", + "vec4 terrainWeights = texture2D(terrainSplatMap, terrainSplatUv) * (0.7 + 0.6 * terrainJitter);", + "terrainWeights = terrainWeights * terrainWeights;", + "terrainWeights /= max(dot(terrainWeights, vec4(1.0)), 0.00001);", + "float terrainCliff = 1.0 - smoothstep(terrainCliffCosines.x, terrainCliffCosines.y, vTerrainUp);", + "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", + "", + "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", + "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", + "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", + "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", + "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "", + "// Less visible repetition: in irregular patches, textures are replaced by a", + "// rotated and shifted copy of themselves, and colors slowly vary.", + "float terrainPatches = 0.0;", + "vec2 terrainUv2 = terrainUv;", + "float terrainColorVariation = 1.0;", + "if (terrainTextureVariation > 0.0) {", + " // Up to half of the ground is covered by the copies, each patch showing", + " // only one of them (mixing them would make them blurry).", + " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", + " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", + " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", + " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", + " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", + " terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", + "}", + "", + "// Height-based blending: the brightness of a texture, compared to its", + "// average, is used as its height. Where layers meet, the high parts (stones,", + "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", + "if (terrainHeightBlending > 0.0) {", + " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + " vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", + " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", + " );", + " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + " // Only painted layers (and the cliff layer) can show.", + " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "}", + "", + "vec3 terrainColor = terrainColorVariation * (", + " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", + " terrainWeights.y * terrainLayerColors[1] * terrainTexture1 +", + " terrainWeights.z * terrainLayerColors[2] * terrainTexture2 +", + " terrainWeights.w * terrainLayerColors[3] * terrainTexture3);", + "", + "// The painted tint multiplies all layers. Wet ground is darker (and", + "// shinier, see the roughness).", + "vec4 terrainTintAndWetness = texture2D(terrainColorMap, terrainSplatUv);", + "float terrainWetness = max(", + " terrainTintAndWetness.a,", + " terrainWetShore.z * (1.0 - smoothstep(terrainWetShore.x, terrainWetShore.x + terrainWetShore.y, vTerrainLocalZ))", + ");", + "terrainColor *= terrainTintAndWetness.rgb * (1.0 - 0.4 * terrainWetness);", + "diffuseColor.rgb *= terrainColor;", + "", + "if (terrainBrush.w > 0.5) {", + " float brushDistance = distance(vTerrainWorldXY, terrainBrush.xy);", + " float ringWidth = max(terrainBrush.z * 0.04, 1.5);", + " float ring = 1.0 - smoothstep(0.0, ringWidth, abs(brushDistance - terrainBrush.z));", + " float disc = brushDistance < terrainBrush.z ? 0.12 : 0.0;", + " diffuseColor.rgb = mix(diffuseColor.rgb, vec3(1.0), max(ring * 0.85, disc));", + "}", + "`;", + "", + "const fragmentShaderRoughnessCode = `", + "roughnessFactor = mix(roughnessFactor, 0.3, terrainWetness);", + "`;", + "", + "const fragmentShaderNormalCode = `", + "if (terrainHasNormalMaps > 0.5) {", + " vec3 terrainMapNormal =", + " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", + " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", + " terrainMapNormal.xy *= terrainNormalMapStrength;", + " // The X and Y of textures follow the X and Y of the 3D world, projected on", + " // the ground (the camera space of the normal is used).", + " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + " if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", + " terrainTangent -= normal * dot(normal, terrainTangent);", + " }", + " terrainTangent = normalize(terrainTangent);", + " vec3 terrainBitangent = cross(normal, terrainTangent);", + " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "}", + "`;", + "", + "let whiteTexture = null;", + "const getWhiteTexture = () => {", + " if (!whiteTexture) {", + " whiteTexture = new THREE.DataTexture(new Uint8Array([255, 255, 255, 255]), 1, 1);", + " whiteTexture.needsUpdate = true;", + " }", + " return whiteTexture;", + "};", + "", + "let flatNormalTexture = null;", + "const getFlatNormalTexture = () => {", + " if (!flatNormalTexture) {", + " flatNormalTexture = new THREE.DataTexture(new Uint8Array([128, 128, 255, 255]), 1, 1);", + " flatNormalTexture.needsUpdate = true;", + " }", + " return flatNormalTexture;", + "};", + "", + "const layerTextures = new WeakMap();", + "const layerNormalMaps = new WeakMap();", + "/**", + " * Textures of the image manager have no mipmaps: they would shimmer when", + " * repeated in the distance.", + " * @param {gdjs.RuntimeGame} game", + " * @param {string} resourceName", + " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " */", + "const getLayerTexture = (game, resourceName, isNormalMap) => {", + " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", + " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", + " const textures = isNormalMap ? layerNormalMaps : layerTextures;", + " let texture = textures.get(imageTexture);", + " if (!texture) {", + " texture = imageTexture.clone();", + " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", + " texture.wrapS = THREE.RepeatWrapping;", + " texture.wrapT = THREE.RepeatWrapping;", + " texture.minFilter = THREE.LinearMipmapLinearFilter;", + " texture.generateMipmaps = true;", + " texture.anisotropy = 4;", + " texture.needsUpdate = true;", + " textures.set(imageTexture, texture);", + " }", + " return texture;", + "};", + "", + "/**", + " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", + " * weights, tint and wetness...), interpolated between samples.", + " * @param {Uint8Array} bytes", + " * @param {number} size", + " */", + "const createGridTexture = (bytes, size) => {", + " const texture = new THREE.DataTexture(bytes, size, size);", + " texture.magFilter = THREE.LinearFilter;", + " texture.minFilter = THREE.LinearFilter;", + " texture.userData.isUploaded = false;", + " texture.onUpdate = () => {", + " texture.userData.isUploaded = true;", + " };", + " return texture;", + "};", + "", + "/**", + " * Send the rows of the changed samples to the GPU, or the whole texture", + " * before its first upload (and in older GDevelop versions).", + " * @param {THREE.DataTexture} texture", + " * @param {SampleRectangle} samples", + " */", + "const uploadGridTextureRows = (texture, samples) => {", + " if (texture.userData.isUploaded && typeof texture.addUpdateRange === 'function') {", + " const size = texture.image.width;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " texture.addUpdateRange((j * size + samples.minI) * 4, (samples.maxI - samples.minI + 1) * 4);", + " }", + " }", + " texture.needsUpdate = true;", + "};", + "", + "class TerrainRenderer {", + " /** @param {Terrain} terrain */", + " constructor(terrain) {", + " this.terrain = terrain;", + " this.group = new THREE.Group();", + " terrain.object.get3DRendererObject().add(this.group);", + " /** @type {Array<{mesh: THREE.Mesh, geometry: THREE.BufferGeometry, firstI: number, firstJ: number, center: THREE.Vector3, lod: number}>} */", + " this.chunks = [];", + " this.chunksPerSide = 0;", + " this.chunkCells = 0;", + " this.chunkSideVertices = 0;", + " this.chunkGridVertices = 0;", + " this.chunkVertices = 0;", + " /** @type {THREE.DataTexture | null} */", + " this.splatTexture = null;", + " /** @type {THREE.DataTexture | null} */", + " this.colorTexture = null;", + " this.uniforms = {", + " terrainSplatMap: { value: getWhiteTexture() },", + " terrainSplatUvScaleAndOffset: { value: new THREE.Vector2() },", + " terrainLayerColors: { value: [new THREE.Color(), new THREE.Color(), new THREE.Color(), new THREE.Color()] },", + " terrainLayerMap0: { value: getWhiteTexture() },", + " terrainLayerMap1: { value: getWhiteTexture() },", + " terrainLayerMap2: { value: getWhiteTexture() },", + " terrainLayerMap3: { value: getWhiteTexture() },", + " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", + " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", + " terrainHasNormalMaps: { value: 0 },", + " terrainNormalMapStrength: { value: 1 },", + " terrainTextureSize: { value: 256 },", + " terrainHeightBlending: { value: 0 },", + " terrainTextureVariation: { value: 0 },", + " terrainCliffLayer: { value: new THREE.Vector4() },", + " terrainCliffCosines: { value: new THREE.Vector2() },", + " terrainBrush: { value: new THREE.Vector4() },", + " terrainColorMap: { value: getWhiteTexture() },", + " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", + " terrainWetShore: { value: new THREE.Vector3() },", + " // Scene units by 3D world unit.", + " terrainWorldScale: { value: 1 },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', '#include \\n' + vertexShaderCode],", + " ], 'Terrain3D');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', fragmentShaderCode],", + " ['#include ', '#include \\n' + fragmentShaderRoughnessCode],", + " ['#include ', '#include \\n' + fragmentShaderNormalCode],", + " ], 'Terrain3D');", + " };", + " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", + " this.hasHoles = false;", + " // Without them, holes would cast shadows.", + " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", + " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " }", + "", + " /**", + " * @param {THREE.MeshDepthMaterial | THREE.MeshDistanceMaterial} material", + " * @returns The material, drawing nothing in holes.", + " */", + " _createHoleDepthMaterial(material) {", + " material.defines = { TERRAIN_HOLES: '' };", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\nvarying vec2 vTerrainLocalXY;'],", + " ['#include ', '#include \\nvTerrainLocalXY = position.xy;'],", + " ], 'Terrain3D shadows');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + holeDepthShaderDeclarations],", + " ['#include ', holeShaderCode + '#include '],", + " ], 'Terrain3D shadows');", + " };", + " material.customProgramCacheKey = () => 'Terrain3DHoles';", + " return material;", + " }", + "", + " /**", + " * Use the shaders drawing holes, or the faster ones without them.", + " * @param {boolean} hasHoles", + " */", + " setHasHoles(hasHoles) {", + " if (hasHoles === this.hasHoles) return;", + " this.hasHoles = hasHoles;", + " // The material has its own defines (STANDARD).", + " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", + " else delete this.material.defines.TERRAIN_HOLES;", + " this.material.needsUpdate = true;", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /** @param {THREE.Mesh} mesh */", + " _setChunkShadowMaterials(mesh) {", + " mesh.customDepthMaterial = this.hasHoles ? this.depthMaterial : undefined;", + " mesh.customDistanceMaterial = this.hasHoles ? this.distanceMaterial : undefined;", + " }", + "", + " /** Recreate all the chunks, for example after the resolution changed. */", + " rebuild() {", + " this.disposeChunks();", + " const { data } = this.terrain;", + " this.chunkCells = getChunkCells(data.resolution);", + " this.chunkSideVertices = this.chunkCells + 1;", + " this.chunkGridVertices = this.chunkSideVertices * this.chunkSideVertices;", + " this.chunkVertices = this.chunkGridVertices + 4 * this.chunkSideVertices;", + " this.chunksPerSide = data.resolution / this.chunkCells;", + " const cellSize = AREA_SIZE / data.resolution;", + " // Sample centers are at the texel centers.", + " this.splatTexture = createGridTexture(data.splat, data.size);", + " this.uniforms.terrainSplatMap.value = this.splatTexture;", + " this.colorTexture = createGridTexture(data.colors, data.size);", + " // Tints are colors chosen like the layer colors.", + " this.colorTexture.colorSpace = THREE.SRGBColorSpace;", + " this.uniforms.terrainColorMap.value = this.colorTexture;", + " this.uniforms.terrainSplatUvScaleAndOffset.value.set(1 / (cellSize * data.size), 0.5 / data.size);", + " for (let chunkJ = 0; chunkJ < this.chunksPerSide; chunkJ++) {", + " for (let chunkI = 0; chunkI < this.chunksPerSide; chunkI++) {", + " const firstI = chunkI * this.chunkCells;", + " const firstJ = chunkJ * this.chunkCells;", + " const positions = new Float32Array(this.chunkVertices * 3);", + " for (let j = 0; j < this.chunkSideVertices; j++) {", + " for (let i = 0; i < this.chunkSideVertices; i++) {", + " const vertex = j * this.chunkSideVertices + i;", + " positions[vertex * 3] = (firstI + i) * cellSize;", + " positions[vertex * 3 + 1] = (firstJ + j) * cellSize;", + " }", + " }", + " // Skirt vertices are below border vertices.", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " positions[skirtVertex * 3] = positions[borderVertex * 3];", + " positions[skirtVertex * 3 + 1] = positions[borderVertex * 3 + 1];", + " });", + " const geometry = new THREE.BufferGeometry();", + " geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.BufferAttribute(new Float32Array(this.chunkVertices * 3), 3));", + " geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[0]));", + " geometry.boundingBox = new THREE.Box3();", + " geometry.boundingSphere = new THREE.Sphere();", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.matrixAutoUpdate = false;", + " // Rays hit the ground at its full resolution, whatever the level of", + " // detail drawn, and go through holes.", + " const chunkCells = this.chunkCells;", + " const terrainData = () => this.terrain.data;", + " const localPoint = new THREE.Vector3();", + " mesh.raycast = function (raycaster, intersects) {", + " const drawnIndex = geometry.index;", + " const firstIntersection = intersects.length;", + " geometry.setIndex(getLodIndex(chunkCells, LOD_STEPS[0]));", + " THREE.Mesh.prototype.raycast.call(this, raycaster, intersects);", + " geometry.setIndex(drawnIndex);", + " const data = terrainData();", + " const cellSize = AREA_SIZE / data.resolution;", + " for (let index = intersects.length - 1; index >= firstIntersection; index--) {", + " this.worldToLocal(localPoint.copy(intersects[index].point));", + " if (data.sampleSolidity(localPoint.x / cellSize, localPoint.y / cellSize) < 0.5) {", + " intersects.splice(index, 1);", + " }", + " }", + " };", + " this._setChunkShadowMaterials(mesh);", + " this.group.add(mesh);", + " this.chunks.push({", + " mesh,", + " geometry,", + " firstI,", + " firstJ,", + " center: new THREE.Vector3(", + " (firstI + this.chunkCells / 2) * cellSize,", + " (firstJ + this.chunkCells / 2) * cellSize,", + " 0", + " ),", + " lod: 0,", + " });", + " }", + " }", + " this.updateSamples(new SampleRectangle().set(0, 0, data.resolution, data.resolution), true);", + " this.updateMaterial();", + " }", + "", + " _forEachSkirtVertex(callback) {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " callback(this.chunkGridVertices + k, k);", + " callback(this.chunkGridVertices + this.chunkSideVertices + k, this.chunkCells * this.chunkSideVertices + k);", + " callback(this.chunkGridVertices + 2 * this.chunkSideVertices + k, k * this.chunkSideVertices);", + " callback(", + " this.chunkGridVertices + 3 * this.chunkSideVertices + k,", + " k * this.chunkSideVertices + this.chunkCells", + " );", + " }", + " }", + "", + " /**", + " * Skirts go down only to the lowest point a coarser neighbor chunk can", + " * draw along the border, so that they can't be seen through holes.", + " * @param {Float32Array} positions", + " */", + " _updateSkirtHeights(positions) {", + " const coarsestStep = LOD_STEPS[LOD_STEPS.length - 1];", + " const borderVertices = [", + " (k) => k,", + " (k) => this.chunkCells * this.chunkSideVertices + k,", + " (k) => k * this.chunkSideVertices,", + " (k) => k * this.chunkSideVertices + this.chunkCells,", + " ];", + " borderVertices.forEach((borderVertex, border) => {", + " for (let k = 0; k < this.chunkSideVertices; k++) {", + " let minZ = Infinity;", + " const from = Math.max(k - coarsestStep, 0);", + " const to = Math.min(k + coarsestStep, this.chunkCells);", + " for (let other = from; other <= to; other++) {", + " minZ = Math.min(minZ, positions[borderVertex(other) * 3 + 2]);", + " }", + " const skirtVertex = this.chunkGridVertices + border * this.chunkSideVertices + k;", + " positions[skirtVertex * 3 + 2] = minZ;", + " }", + " });", + " }", + "", + " /**", + " * Update the vertices of the chunks sharing the given samples.", + " * @param {SampleRectangle} samples", + " * @param {boolean} hasPaintChanged", + " */", + " updateSamples(samples, hasPaintChanged) {", + " if (samples.isEmpty()) return;", + " const { data } = this.terrain;", + " const cellSize = AREA_SIZE / data.resolution;", + " const slopeFactor = AREA_DEPTH / cellSize;", + " // Normals of samples next to changed ones change too.", + " const minI = Math.max(samples.minI - 1, 0);", + " const minJ = Math.max(samples.minJ - 1, 0);", + " const maxI = Math.min(samples.maxI + 1, data.resolution);", + " const maxJ = Math.min(samples.maxJ + 1, data.resolution);", + " const firstChunkI = Math.max(Math.ceil(minI / this.chunkCells) - 1, 0);", + " const firstChunkJ = Math.max(Math.ceil(minJ / this.chunkCells) - 1, 0);", + " const lastChunkI = Math.min(Math.floor(maxI / this.chunkCells), this.chunksPerSide - 1);", + " const lastChunkJ = Math.min(Math.floor(maxJ / this.chunkCells), this.chunksPerSide - 1);", + "", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " const chunk = this.chunks[chunkJ * this.chunksPerSide + chunkI];", + " const positions = chunk.geometry.attributes.position.array;", + " const normals = chunk.geometry.attributes.normal.array;", + " const fromI = Math.max(minI - chunk.firstI, 0);", + " const toI = Math.min(maxI - chunk.firstI, this.chunkCells);", + " const fromJ = Math.max(minJ - chunk.firstJ, 0);", + " const toJ = Math.min(maxJ - chunk.firstJ, this.chunkCells);", + " for (let j = fromJ; j <= toJ; j++) {", + " const gridJ = chunk.firstJ + j;", + " for (let i = fromI; i <= toI; i++) {", + " const gridI = chunk.firstI + i;", + " const vertex = j * this.chunkSideVertices + i;", + " const sample = gridJ * data.size + gridI;", + " positions[vertex * 3 + 2] = data.heights[sample] * AREA_DEPTH;", + "", + " const leftI = Math.max(gridI - 1, 0);", + " const rightI = Math.min(gridI + 1, data.resolution);", + " const upJ = Math.max(gridJ - 1, 0);", + " const downJ = Math.min(gridJ + 1, data.resolution);", + " const nx =", + " ((data.getHeight(leftI, gridJ) - data.getHeight(rightI, gridJ)) * slopeFactor) /", + " (rightI - leftI);", + " const ny =", + " ((data.getHeight(gridI, upJ) - data.getHeight(gridI, downJ)) * slopeFactor) /", + " (downJ - upJ);", + " const inverseLength = 1 / Math.sqrt(nx * nx + ny * ny + 1);", + " normals[vertex * 3] = nx * inverseLength;", + " normals[vertex * 3 + 1] = ny * inverseLength;", + " normals[vertex * 3 + 2] = inverseLength;", + " }", + " }", + " this._forEachSkirtVertex((skirtVertex, borderVertex) => {", + " for (let axis = 0; axis < 3; axis++) {", + " normals[skirtVertex * 3 + axis] = normals[borderVertex * 3 + axis];", + " }", + " });", + " this._updateSkirtHeights(positions);", + " let maxZ = 0;", + " for (let vertex = 0; vertex < this.chunkGridVertices; vertex++) {", + " maxZ = Math.max(maxZ, positions[vertex * 3 + 2]);", + " }", + " const chunkSize = this.chunkCells * cellSize;", + " chunk.geometry.boundingBox.min.set(chunk.firstI * cellSize, chunk.firstJ * cellSize, 0);", + " chunk.geometry.boundingBox.max.set(", + " chunk.firstI * cellSize + chunkSize,", + " chunk.firstJ * cellSize + chunkSize,", + " maxZ", + " );", + " chunk.geometry.boundingBox.getBoundingSphere(chunk.geometry.boundingSphere);", + " chunk.center.z = maxZ / 2;", + " chunk.geometry.attributes.position.needsUpdate = true;", + " chunk.geometry.attributes.normal.needsUpdate = true;", + " }", + " }", + " if (hasPaintChanged) {", + " // The data may have been replaced by one with the same resolution.", + " this.splatTexture.image.data = data.splat;", + " uploadGridTextureRows(this.splatTexture, samples);", + " this.colorTexture.image.data = data.colors;", + " uploadGridTextureRows(this.colorTexture, samples);", + " }", + " }", + "", + " updateMaterial() {", + " const { object } = this.terrain;", + " const game = object.getRuntimeScene().getGame();", + " const colors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " const textures = [", + " object._getLayer1Texture(),", + " object._getLayer2Texture(),", + " object._getLayer3Texture(),", + " object._getLayer4Texture(),", + " ];", + " const normalMaps = [", + " object._getLayer1NormalMap(),", + " object._getLayer2NormalMap(),", + " object._getLayer3NormalMap(),", + " object._getLayer4NormalMap(),", + " ];", + " for (let layer = 0; layer < LAYER_COUNT; layer++) {", + " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", + " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " }", + " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", + " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", + " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", + " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + "", + " const cliffLayer = parseInt(object._getCliffLayer(), 10);", + " const cliffAngle = gdjs.toRad(object._getCliffAngle());", + " const cliffBlendAngle = gdjs.toRad(4);", + " this.uniforms.terrainCliffLayer.value.set(", + " cliffLayer === 1 ? 1 : 0,", + " cliffLayer === 2 ? 1 : 0,", + " cliffLayer === 3 ? 1 : 0,", + " cliffLayer === 4 ? 1 : 0", + " );", + " this.uniforms.terrainCliffCosines.value.set(", + " Math.cos(cliffAngle + cliffBlendAngle),", + " Math.cos(cliffAngle - cliffBlendAngle)", + " );", + "", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " for (const chunk of this.chunks) {", + " chunk.mesh.castShadow = castShadow;", + " chunk.mesh.receiveShadow = receiveShadow;", + " }", + " }", + "", + " /**", + " * Show the brush circle of the editor.", + " * @param {THREE.Vector3 | null} localPosition", + " * @param {number} radius In scene units.", + " */", + " setBrush(localPosition, radius) {", + " const brush = this.uniforms.terrainBrush.value;", + " if (!localPosition) {", + " brush.w = 0;", + " return;", + " }", + " this.group.updateWorldMatrix(true, false);", + " const worldPosition = this._chunkPosition.copy(localPosition).applyMatrix4(this.group.matrixWorld);", + " const worldScale = this.uniforms.terrainWorldScale.value;", + " brush.set(worldPosition.x * worldScale, worldPosition.y * worldScale, radius, 1);", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " updateLevelsOfDetail(camera) {", + " if (!camera || !this.group.visible) return;", + " const matrixWorld = this.group.matrixWorld;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " this._scale.setFromMatrixScale(matrixWorld);", + " const cellSize = AREA_SIZE / this.terrain.data.resolution;", + " const chunkWorldSize = this.chunkCells * cellSize * Math.max(this._scale.x, this._scale.y);", + " for (const chunk of this.chunks) {", + " const distance =", + " this._chunkPosition.copy(chunk.center).applyMatrix4(matrixWorld).distanceTo(this._cameraPosition) /", + " chunkWorldSize;", + " let lod = LOD_DISTANCES.length - 1;", + " while (lod > 0 && distance < LOD_DISTANCES[lod]) lod--;", + " if (lod !== chunk.lod) {", + " chunk.lod = lod;", + " chunk.geometry.setIndex(getLodIndex(this.chunkCells, LOD_STEPS[lod]));", + " }", + " }", + " }", + "", + " disposeChunks() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " // The index is shared by all chunks: it must stay on the GPU.", + " chunk.geometry.setIndex(null);", + " chunk.geometry.dispose();", + " }", + " this.chunks.length = 0;", + " if (this.splatTexture) this.splatTexture.dispose();", + " this.splatTexture = null;", + " if (this.colorTexture) this.colorTexture.dispose();", + " this.colorTexture = null;", + " }", + "", + " dispose() {", + " this.disposeChunks();", + " this.material.dispose();", + " this.depthMaterial.dispose();", + " this.distanceMaterial.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "/**", + " * Makes a Physics3D behavior use a height field shape following the terrain.", + " * Changes of heights are applied to the shape without recreating it.", + " * @implements {gdjs.Physics3DRuntimeBehavior.BodyUpdater}", + " */", + "class TerrainBodyUpdater {", + " /**", + " * @param {Terrain} terrain", + " * @param {gdjs.Physics3DRuntimeBehavior} physics", + " */", + " constructor(terrain, physics) {", + " this.terrain = terrain;", + " this.physics = physics;", + " this.defaultBodyUpdater = physics.bodyUpdater;", + " this.changedSamples = new SampleRectangle();", + " /** @type {Jolt.HeightFieldShape | null} */", + " this.heightField = null;", + " this.heightScale = 1;", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " this.bodyX = 0;", + " this.bodyY = 0;", + " this.bodyZ = 0;", + " this.bodyHeight = 0;", + " physics.bodyType = 'Static';", + " physics.bodyUpdater = this;", + " }", + "", + " createShape() {", + " const { data, object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const { size } = data;", + " this.heightScale = object.getDepth() * worldInvScale;", + "", + " // Changes of heights (SetHeights) break collisions unless the sample", + " // count is a power of 2: extra samples have no collision.", + " const sampleCount = Math.pow(2, Math.ceil(Math.log2(size)));", + " const settings = new Jolt.HeightFieldShapeSettings();", + " settings.mScale.Set(", + " (object.getWidth() / data.resolution) * worldInvScale,", + " 1,", + " (object.getHeight() / data.resolution) * worldInvScale", + " );", + " settings.mSampleCount = sampleCount;", + " settings.mBlockSize = 4;", + " // Allows later changes of heights on the whole depth of the object.", + " settings.mMinHeightValue = 0;", + " settings.mMaxHeightValue = this.heightScale;", + " settings.mHeightSamples.resize(sampleCount * sampleCount);", + " const samples = new Float32Array(", + " Jolt.HEAPF32.buffer,", + " Jolt.getPointer(settings.mHeightSamples.data()),", + " sampleCount * sampleCount", + " );", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " samples.fill(noCollision);", + " // Height fields go along X and Z: rows are flipped so that, once", + " // rotated to have heights along Z, rows go along Y.", + " for (let j = 0; j < size; j++) {", + " const row = (size - 1 - j) * sampleCount;", + " for (let i = 0; i < size; i++) {", + " samples[row + i] = this._getSampleHeight(j * size + i, noCollision);", + " }", + " }", + " const shape = settings.Create().Get();", + " Jolt.destroy(settings);", + " this.heightField = Jolt.castObject(shape, Jolt.HeightFieldShape);", + " this.changedSamples.clear();", + " return shape;", + " }", + "", + " /** @returns {number} The height of a sample in the shape, or no collision in a hole. */", + " _getSampleHeight(index, noCollision) {", + " const height = this.terrain.surfaceHeights[index];", + " return Number.isNaN(height) ? noCollision : height * this.heightScale;", + " }", + "", + " _getBodyPosition() {", + " const { object } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " this.bodyX = object.getX();", + " this.bodyY = object.getY();", + " this.bodyZ = object.getZ();", + " // The origin of the height field is at the bottom of the terrain (see createShape).", + " this.bodyHeight = object.getHeight();", + " return this.physics._sharedData.getRVec3(", + " object.getX() * worldInvScale,", + " (object.getY() + object.getHeight()) * worldInvScale,", + " object.getZ() * worldInvScale", + " );", + " }", + "", + " _getBodyRotation() {", + " // A quarter turn around X: heights go along Z.", + " return this.physics._sharedData.getQuat(Math.SQRT1_2, 0, 0, Math.SQRT1_2);", + " }", + "", + " createAndAddBody() {", + " const { physics } = this;", + " const { bodyInterface } = physics._sharedData;", + " const shape = this.createShape();", + " const settings = new Jolt.BodyCreationSettings(", + " shape,", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EMotionType_Static,", + " physics.getBodyLayer()", + " );", + " settings.mFriction = physics.friction;", + " settings.mRestitution = physics.restitution;", + " const body = bodyInterface.CreateBody(settings);", + " Jolt.destroy(settings);", + " bodyInterface.AddBody(body.GetID(), Jolt.EActivation_DontActivate);", + " return body;", + " }", + "", + " updateObjectFromBody() {", + " // The terrain is static: the body never moves it.", + " }", + "", + " updateBodyFromObject() {", + " const { physics } = this;", + " const body = physics._body;", + " if (!body) return;", + " const { object } = this.terrain;", + " const { bodyInterface } = physics._sharedData;", + " if (", + " object.getX() !== this.bodyX ||", + " object.getY() !== this.bodyY ||", + " object.getZ() !== this.bodyZ ||", + " object.getHeight() !== this.bodyHeight", + " ) {", + " bodyInterface.SetPositionAndRotation(", + " body.GetID(),", + " this._getBodyPosition(),", + " this._getBodyRotation(),", + " Jolt.EActivation_DontActivate", + " );", + " }", + " if (!this.changedSamples.isEmpty()) {", + " this._applyChangedHeights(body);", + " }", + " }", + "", + " _applyChangedHeights(body) {", + " const { data } = this.terrain;", + " const { size } = data;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Jolt only changes blocks of samples. Rows are flipped and extra", + " // samples have no collision (see createShape).", + " const blockSize = this.heightField.GetBlockSize();", + " const sampleCount = this.heightField.GetSampleCount();", + " const alignDown = (value) => Math.floor(value / blockSize) * blockSize;", + " const alignUp = (value) => Math.min(Math.ceil(value / blockSize) * blockSize, sampleCount);", + " const firstX = alignDown(minI);", + " const firstRow = alignDown(size - 1 - maxJ);", + " const width = alignUp(maxI + 1) - firstX;", + " const height = alignUp(size - minJ) - firstRow;", + " if (width * height > this.heightsBufferLength) {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferLength = width * height;", + " this.heightsBufferPointer = Jolt._webidl_malloc(this.heightsBufferLength * 4);", + " }", + " const heights = new Float32Array(Jolt.HEAPF32.buffer, this.heightsBufferPointer, width * height);", + " const noCollision = Jolt.HeightFieldShapeConstantValues.prototype.cNoCollisionValue;", + " for (let row = 0; row < height; row++) {", + " const j = size - 1 - (firstRow + row);", + " for (let column = 0; column < width; column++) {", + " const i = firstX + column;", + " heights[row * width + column] =", + " i < size && j >= 0 ? this._getSampleHeight(j * size + i, noCollision) : noCollision;", + " }", + " }", + " const sharedData = this.physics._sharedData;", + " this.heightField.SetHeights(", + " firstX,", + " firstRow,", + " width,", + " height,", + " this.heightsBufferPointer,", + " width,", + " sharedData.jolt.GetTempAllocator()", + " );", + " sharedData.bodyInterface.NotifyShapeChanged(", + " body.GetID(),", + " sharedData.getVec3(0, 0, 0),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " /** Bodies sleeping on the changed area would otherwise float or sink. */", + " _wakeUpBodiesOnChangedSamples() {", + " const { object, data } = this.terrain;", + " const worldInvScale = this.physics._sharedData.worldInvScale;", + " const cellWidth = object.getWidth() / data.resolution;", + " const cellHeight = object.getHeight() / data.resolution;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " const min = new Jolt.Vec3(", + " (object.getX() + (minI - 1) * cellWidth) * worldInvScale,", + " (object.getY() + (minJ - 1) * cellHeight) * worldInvScale,", + " (object.getZ() - 1) * worldInvScale", + " );", + " const max = new Jolt.Vec3(", + " (object.getX() + (maxI + 1) * cellWidth) * worldInvScale,", + " (object.getY() + (maxJ + 1) * cellHeight) * worldInvScale,", + " (object.getZ() + object.getDepth() + 1) * worldInvScale", + " );", + " const box = new Jolt.AABox(min, max);", + " const broadPhaseLayerFilter = new Jolt.BroadPhaseLayerFilter();", + " const objectLayerFilter = new Jolt.ObjectLayerFilter();", + " this.physics._sharedData.bodyInterface.ActivateBodiesInAABox(box, broadPhaseLayerFilter, objectLayerFilter);", + " Jolt.destroy(min);", + " Jolt.destroy(max);", + " Jolt.destroy(box);", + " Jolt.destroy(broadPhaseLayerFilter);", + " Jolt.destroy(objectLayerFilter);", + " }", + "", + " recreateShape() {", + " const body = this.physics._body;", + " if (!body) return;", + " this.physics._sharedData.bodyInterface.SetShape(", + " body.GetID(),", + " this.createShape(),", + " false,", + " Jolt.EActivation_DontActivate", + " );", + " const { resolution } = this.terrain.data;", + " this.changedSamples.set(0, 0, resolution, resolution);", + " this._wakeUpBodiesOnChangedSamples();", + " this.changedSamples.clear();", + " }", + "", + " destroyBody() {", + " this.defaultBodyUpdater.destroyBody();", + " this.heightField = null;", + " }", + "", + " dispose() {", + " if (this.heightsBufferPointer) Jolt._webidl_free(this.heightsBufferPointer);", + " this.heightsBufferPointer = 0;", + " this.heightsBufferLength = 0;", + " }", + "}", + "", + "/** @param {TerrainData} data */", + "const copyTerrainData = (data) => {", + " const copy = new TerrainData(data.resolution);", + " copy.copyFrom(data);", + " return copy;", + "};", + "", + "// Generating a relief or reading an image is long for big terrains, and done", + "// for every instance and every hot-reload: the results are kept.", + "const baseDataCache = new Map();", + "const MAX_CACHED_BASE_DATA = 8;", + "// Changes of the shape of a terrain kept for consumers of its surface that", + "// missed some versions: older changes update the whole surface.", + "const MAX_SURFACE_CHANGES = 64;", + "// Unique among all terrains: a terrain replaced by another one never has its version.", + "let lastGroundVersion = 0;", + "", + "/**", + " * The terrain of a Terrain3D object: its data, how it's drawn and its", + " * surface (for collisions and navigation meshes). Positions are in the scene.", + " */", + "class Terrain {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " /** @type {TerrainData} */", + " this.data = new TerrainData(DEFAULT_RESOLUTION);", + " /** The data before any sculpting or painting, from the relief or heightmap. */", + " this.baseData = this.data;", + " this.renderer = new TerrainRenderer(this);", + " /** @type {TerrainBodyUpdater[]} */", + " this.bodyUpdaters = [];", + " this.changedSamples = new SampleRectangle();", + " this.hasPaintChanged = false;", + " /** Increased each time the ground changes, for objects following it (like grass). */", + " this.version = 0;", + " /** Increased each time the shape of the ground changes (not its paint or position). */", + " this.surfaceVersion = 0;", + " /**", + " * The last changes of the shape of the ground, for `getChangedArea`.", + " * @type {Array<{version: number, samples: SampleRectangle}>}", + " */", + " this.surfaceChanges = [];", + " /** The changes since this version are all in `surfaceChanges`. */", + " this.surfaceChangesStartVersion = 0;", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._strokeChangedSamples = new SampleRectangle();", + " /** The properties the data was loaded from, to reload it only if they change. */", + " this.loadedFrom = '';", + " /** The heightmap image being loaded: the relief is used until it is. */", + " this.loadingHeightmapImage = '';", + " this.isDisposed = false;", + " /** The last value of the sculpt data property read or saved. */", + " this.sculptData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedSculptData = [];", + " /** The heights of the surface: the heights of the data, and NaN in holes. */", + " this.surfaceHeights = new Float32Array(0);", + " this.loadFromProperties();", + " this._transform = this._getTransform();", + " getGrounds(object.getRuntimeScene()).add(this);", + " /**", + " * The shape of the ground, for the physics engine and navigation meshes.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.surfaceVersion,", + " getChangedArea: (sinceVersion) => this.getChangedArea(sinceVersion),", + " getTriangles: () => null,", + " getHeightField: () => ({ columns: this.data.size, rows: this.data.size, heights: this.surfaceHeights }),", + " };", + " if (typeof object.setSurface === 'function') {", + " object.setSurface(this.surface);", + " } else if (gdjs.Physics3DRuntimeBehavior) {", + " // Older GDevelop versions don't use surfaces.", + " for (const behavior of object._behaviors) {", + " if (behavior instanceof gdjs.Physics3DRuntimeBehavior) {", + " this.bodyUpdaters.push(new TerrainBodyUpdater(this, behavior));", + " }", + " }", + " }", + " }", + "", + " _getSourceProperties() {", + " const { object } = this;", + " return [", + " object._getResolution(),", + " object._getRelief(),", + " object._getSeed(),", + " object._getHeightmapImage(),", + " object._getEdits(),", + " ].join('|');", + " }", + "", + " loadFromProperties() {", + " const { object } = this;", + " const resolution = parseInt(object._getResolution(), 10);", + " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", + " this.sculptData = object._getSculptData();", + " this.loadedFrom = this._getSourceProperties();", + "", + " this.baseData = this._getBaseData(validResolution);", + " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", + " if (data && data.resolution !== validResolution) {", + " data = data.resampled(validResolution);", + " }", + " this.setData(data || copyTerrainData(this.baseData));", + " }", + "", + " /**", + " * @param {number} resolution", + " * @returns {TerrainData} The data from the relief or the heightmap, shared: it must not be changed.", + " */", + " _getBaseData(resolution) {", + " const { object } = this;", + " const key = [resolution, object._getRelief(), object._getSeed(), object._getHeightmapImage(), object._getEdits()].join('|');", + " const cachedData = baseDataCache.get(key);", + " if (cachedData) return cachedData;", + "", + " const data = new TerrainData(resolution);", + " const heightmapImage = object._getHeightmapImage();", + " const isHeightmapLoaded =", + " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", + " if (!isHeightmapLoaded) {", + " relief.generate(data, object._getRelief(), object._getSeed());", + " if (heightmapImage) this._reloadOnceLoaded(heightmapImage);", + " }", + " edits.apply(data, object._getEdits());", + " // Not kept if the image is missing: it may be loaded later.", + " if (isHeightmapLoaded || !heightmapImage) baseDataCache.set(key, data);", + " if (baseDataCache.size > MAX_CACHED_BASE_DATA) {", + " baseDataCache.delete(baseDataCache.keys().next().value);", + " }", + " return data;", + " }", + "", + " /** @param {TerrainData} data */", + " setData(data) {", + " this.version = ++lastGroundVersion;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.length = 0;", + " this.surfaceChangesStartVersion = this.version;", + " const hasSameResolution = data.resolution === this.data.resolution && this.renderer.chunks.length > 0;", + " this.data = data;", + " const allSamples = new SampleRectangle().set(0, 0, data.resolution, data.resolution);", + " this.surfaceHeights = new Float32Array(data.heights.length);", + " this.renderer.setHasHoles(false);", + " this._updateSurfaceHeights(allSamples);", + " if (hasSameResolution) {", + " this.renderer.updateSamples(allSamples, true);", + " } else {", + " this.renderer.rebuild();", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.recreateShape();", + " }", + " }", + "", + " onHotReloading() {", + " const sculptData = this.object._getSculptData();", + " const savedIndex = this.savedSculptData.indexOf(sculptData);", + " if (savedIndex !== -1 && this._getSourceProperties() === this.loadedFrom) {", + " // The terrain already has this data, or newer changes.", + " this.savedSculptData.splice(0, savedIndex + 1);", + " } else if (sculptData !== this.sculptData || this._getSourceProperties() !== this.loadedFrom) {", + " this.savedSculptData.length = 0;", + " this.loadFromProperties();", + " }", + " this.renderer.updateMaterial();", + " }", + "", + " /** @returns {string} The data to save in the sculpt data property. */", + " save() {", + " this.sculptData = codec.encode(this.data, this.baseData);", + " this.savedSculptData.push(this.sculptData);", + " return this.sculptData;", + " }", + "", + " getCellWidth() {", + " return this.object.getWidth() / this.data.resolution;", + " }", + "", + " getCellHeight() {", + " return this.object.getHeight() / this.data.resolution;", + " }", + "", + " _toGridX(x) {", + " return (x - this.object.getX()) / this.getCellWidth();", + " }", + "", + " _toGridY(y) {", + " return (y - this.object.getY()) / this.getCellHeight();", + " }", + "", + " /** @returns {number} The Z position of the ground. */", + " getHeightAt(x, y) {", + " return this.object.getZ() + this.data.sampleHeight(this._toGridX(x), this._toGridY(y)) * this.object.getDepth();", + " }", + "", + " /** @returns {number} The angle of the ground with the horizontal, in degrees. */", + " getSlopeAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " const { data } = this;", + " const depth = this.object.getDepth();", + " const slopeX = ((data.sampleHeight(gridX + 0.5, gridY) - data.sampleHeight(gridX - 0.5, gridY)) * depth) / this.getCellWidth();", + " const slopeY = ((data.sampleHeight(gridX, gridY + 0.5) - data.sampleHeight(gridX, gridY - 0.5)) * depth) / this.getCellHeight();", + " return gdjs.toDegrees(Math.atan(Math.hypot(slopeX, slopeY)));", + " }", + "", + " /** @returns {number} The layer painted the most, from 1 to 4. */", + " getLayerAt(x, y) {", + " return this.data.getDominantLayer(this._toGridX(x), this._toGridY(y)) + 1;", + " }", + "", + " /**", + " * @param {number} layer From 1 to 4.", + " * @returns {number} How much the layer is painted, from 0 to 1.", + " */", + " getLayerWeightAt(x, y, layer) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " return this.data.sampleLayerWeight(this._toGridX(x), this._toGridY(y), layerIndex);", + " }", + "", + " /** @returns {number[]} The painted tint: red, green and blue, from 0 to 255 (white when there is none). */", + " getTintAt(x, y) {", + " const gridX = this._toGridX(x);", + " const gridY = this._toGridY(y);", + " return [0, 1, 2].map((channel) => Math.round(this.data.sampleColor(gridX, gridY, channel) * 255));", + " }", + "", + " /** @returns {number} How wet the ground is, from 0 (dry) to 1, painted or near the water (see the wet shore). */", + " getWetnessAt(x, y) {", + " const paintedWetness = this.data.sampleColor(this._toGridX(x), this._toGridY(y), 3);", + " const { object } = this;", + " if (!object._getWetShore()) return paintedWetness;", + " const fade = Math.max(object._getWetShoreFade(), 0.001);", + " const shoreWetness = clamp01((object._getWetShoreZ() + fade - this.getHeightAt(x, y)) / fade);", + " // Like the smoothstep of the shader.", + " return Math.max(paintedWetness, shoreWetness * shoreWetness * (3 - 2 * shoreWetness));", + " }", + "", + " _isInArea(x, y) {", + " const { object } = this;", + " return (", + " x >= object.getX() &&", + " x <= object.getX() + object.getWidth() &&", + " y >= object.getY() &&", + " y <= object.getY() + object.getHeight()", + " );", + " }", + "", + " /** @returns {boolean} true if the position is above or under the terrain, and not in a hole. */", + " containsPoint(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) >= 0.5;", + " }", + "", + " /** @returns {boolean} true if there is a hole in the terrain at the position, like what is drawn. */", + " isHoleAt(x, y) {", + " return this._isInArea(x, y) && this.data.sampleSolidity(this._toGridX(x), this._toGridY(y)) < 0.5;", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const stroke = this._stroke;", + " stroke.cellWidth = this.getCellWidth();", + " stroke.cellHeight = this.getCellHeight();", + " stroke.ax = x1 - this.object.getX();", + " stroke.ay = y1 - this.object.getY();", + " stroke.bx = x2 - this.object.getX();", + " stroke.by = y2 - this.object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @param {boolean} haveHeightsChanged false when only the paint changed.", + " */", + " _onSamplesChanged(samples, haveHeightsChanged) {", + " if (samples.isEmpty()) return;", + " this.version = ++lastGroundVersion;", + " this.changedSamples.add(samples);", + " // Painting changes the surface when it makes holes or fills them.", + " const hasSurfaceChanged = this._updateSurfaceHeights(samples);", + " if (!haveHeightsChanged && !hasSurfaceChanged) return;", + " this.surfaceVersion = this.version;", + " this.surfaceChanges.push({ version: this.version, samples: new SampleRectangle().set(samples.minI, samples.minJ, samples.maxI, samples.maxJ) });", + " if (this.surfaceChanges.length > MAX_SURFACE_CHANGES) {", + " this.surfaceChangesStartVersion = this.surfaceChanges.shift().version;", + " }", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.changedSamples.add(samples);", + " }", + " }", + "", + " /**", + " * @param {SampleRectangle} samples", + " * @returns {boolean} true if heights of the surface changed, or holes were made or filled.", + " */", + " _updateSurfaceHeights(samples) {", + " const { data, surfaceHeights } = this;", + " let hasChanged = false;", + " let hasHoles = false;", + " for (let j = samples.minJ; j <= samples.maxJ; j++) {", + " for (let i = samples.minI; i <= samples.maxI; i++) {", + " const index = j * data.size + i;", + " const isHole = data.isHole(index);", + " const height = isHole ? NaN : data.heights[index];", + " const previousHeight = surfaceHeights[index];", + " if (isHole) {", + " hasHoles = true;", + " if (Number.isNaN(previousHeight)) continue;", + " } else if (height === previousHeight) {", + " continue;", + " }", + " surfaceHeights[index] = height;", + " hasChanged = true;", + " }", + " }", + " // Filled holes keep the shaders drawing holes until the data is loaded again.", + " if (hasHoles) this.renderer.setHasHoles(true);", + " return hasChanged;", + " }", + "", + " /** @param {number} height In scene units, negative to lower the ground. */", + " raise(x1, y1, x2, y2, radius, height) {", + " const samples = this._strokeChangedSamples;", + " brushes.raise(this.data, this._getStroke(x1, y1, x2, y2, radius), height / this.object.getDepth(), samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} z The Z position to flatten the ground to. */", + " /** @param {number} [toZ] The Z position at the end of the segment, for a slope. The same as z by default. */", + " flatten(x1, y1, x2, y2, radius, z, strength, toZ = z) {", + " const samples = this._strokeChangedSamples;", + " const toHeight = (value) => (value - this.object.getZ()) / this.object.getDepth();", + " brushes.flatten(this.data, this._getStroke(x1, y1, x2, y2, radius), toHeight(z), strength, samples, toHeight(toZ));", + " this._onSamplesChanged(samples, true);", + " }", + "", + " smooth(x1, y1, x2, y2, radius, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.smooth(this.data, this._getStroke(x1, y1, x2, y2, radius), strength, samples);", + " this._onSamplesChanged(samples, true);", + " }", + "", + " /** @param {number} layer From 1 to 4. */", + " paint(x1, y1, x2, y2, radius, layer, strength) {", + " const layerIndex = clampInteger(layer - 1, 0, LAYER_COUNT - 1);", + " const samples = this._strokeChangedSamples;", + " brushes.paint(this.data, this._getStroke(x1, y1, x2, y2, radius), layerIndex, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number[]} color The red, green and blue (0-255) of the tint: white removes it. */", + " tint(x1, y1, x2, y2, radius, color, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.tint(this.data, this._getStroke(x1, y1, x2, y2, radius), color, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** @param {number} wetness From 0 (dry) to 1. */", + " wet(x1, y1, x2, y2, radius, wetness, strength) {", + " const samples = this._strokeChangedSamples;", + " brushes.wet(this.data, this._getStroke(x1, y1, x2, y2, radius), wetness, strength, samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Make a hole around a segment (`fillHoles` fills it again). */", + " makeHole(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.hole(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /** Fill the holes around a segment with the layers of the ground around them. */", + " fillHoles(x1, y1, x2, y2, radius) {", + " const samples = this._strokeChangedSamples;", + " brushes.fill(this.data, this._getStroke(x1, y1, x2, y2, radius), samples);", + " this.hasPaintChanged = true;", + " this._onSamplesChanged(samples, false);", + " }", + "", + " /**", + " * Make the entrance of a tunnel or a cave: a hole, with the ground in", + " * front of it flattened to the floor of the tunnel.", + " * @param {number} angle The direction going into the ground, in degrees.", + " * @param {number} floorZ", + " * @param {number} length The length of the flat ground in front of the entrance.", + " */", + " carveEntrance(x, y, radius, angle, floorZ, length) {", + " const directionX = Math.cos(gdjs.toRad(angle));", + " const directionY = Math.sin(gdjs.toRad(angle));", + " this.flatten(x - directionX * length, y - directionY * length, x, y, radius * 1.5, floorZ, 1);", + " this.makeHole(x, y, x + directionX * radius, y + directionY * radius, radius);", + " }", + "", + " generate(reliefName, seed) {", + " this.baseData = new TerrainData(this.data.resolution);", + " relief.generate(this.baseData, reliefName, seed);", + " this.setData(copyTerrainData(this.baseData));", + " }", + "", + " loadHeightmap(imageResourceName) {", + " const baseData = new TerrainData(this.data.resolution);", + " if (loadHeightsFromImage(baseData, this.object.getRuntimeScene().getGame(), imageResourceName)) {", + " baseData.splat.set(this.data.splat);", + " baseData.colors.set(this.data.colors);", + " this.baseData = baseData;", + " this.setData(copyTerrainData(baseData));", + " }", + " }", + "", + " /** @param {gdjs.RuntimeObject[]} objects */", + " placeOnGround(objects) {", + " for (const object of objects) {", + " if (object === this.object || !gdjs.Base3DHandler.is3D(object)) continue;", + " const groundZ = this.getHeightAt(object.getCenterXInScene(), object.getCenterYInScene());", + " // The origin of the object is not always at its bottom.", + " object.setZ(groundZ + object.getZ() - object.getUnrotatedAABBMinZ());", + " }", + " }", + "", + " /**", + " * @returns {THREE.Vector3 | null} The point of the ground under the cursor,", + " * in the terrain group coordinates. Holes are hit too, so that brushes can fill them.", + " */", + " raycastFromCursor(game, raycaster, ndc) {", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " raycaster.setFromCamera(ndc, camera);", + " this.renderer.group.updateWorldMatrix(true, false);", + " const ray = raycaster.ray.clone().applyMatrix4(this.renderer.group.matrixWorld.clone().invert());", + " ray.direction.normalize();", + "", + " const box = new THREE.Box3(new THREE.Vector3(0, 0, 0), new THREE.Vector3(AREA_SIZE, AREA_SIZE, AREA_DEPTH));", + " const entry = box.containsPoint(ray.origin) ? ray.origin.clone() : ray.intersectBox(box, new THREE.Vector3());", + " if (!entry) return null;", + " const cellSize = AREA_SIZE / this.data.resolution;", + " const groundZAt = (point) => this.data.sampleHeight(point.x / cellSize, point.y / cellSize) * AREA_DEPTH;", + " const step = cellSize / 2;", + " const point = entry.clone();", + " const previousPoint = entry.clone();", + " for (let distance = 0; distance < AREA_SIZE * 2; distance += step) {", + " if (point.z <= groundZAt(point)) {", + " // Refine between the last point above the ground and this one.", + " for (let iteration = 0; iteration < 8; iteration++) {", + " const middle = previousPoint.clone().lerp(point, 0.5);", + " if (middle.z <= groundZAt(middle)) point.copy(middle);", + " else previousPoint.copy(middle);", + " }", + " return point;", + " }", + " if (!box.containsPoint(point)) return null;", + " previousPoint.copy(point);", + " point.addScaledVector(ray.direction, step);", + " }", + " return null;", + " }", + "", + " /**", + " * @param {THREE.Vector3} localPosition In the terrain group coordinates (like from `raycastFromCursor`).", + " * @returns {{x: number, y: number, z: number}} The position in the scene.", + " */", + " toScenePosition(localPosition) {", + " const { object } = this;", + " return {", + " x: object.getX() + (localPosition.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (localPosition.y / AREA_SIZE) * object.getHeight(),", + " z: object.getZ() + (localPosition.z / AREA_DEPTH) * object.getDepth(),", + " };", + " }", + "", + " /** Draw the changes of the ground (collisions are updated by the physics engine). */", + " applyChanges() {", + " this.renderer.updateSamples(this.changedSamples, this.hasPaintChanged);", + " this.changedSamples.clear();", + " this.hasPaintChanged = false;", + " }", + "", + " /** @returns {number} A number changing each time the ground changes (see `getGrounds`). */", + " getVersion() {", + " return this.version;", + " }", + "", + " /**", + " * @param {number} sinceVersion", + " * @returns {gdjs.SurfaceArea | null} The part of the ground whose shape changed since the version (see `gdjs.Surface`).", + " */", + " getChangedArea(sinceVersion) {", + " if (sinceVersion < this.surfaceChangesStartVersion) return null;", + " const samples = new SampleRectangle();", + " for (const change of this.surfaceChanges) {", + " if (change.version > sinceVersion) samples.add(change.samples);", + " }", + " if (samples.isEmpty()) return { minX: 0, minY: 0, maxX: 0, maxY: 0 };", + " const { resolution } = this.data;", + " return {", + " minX: samples.minI / resolution,", + " minY: samples.minJ / resolution,", + " maxX: samples.maxI / resolution,", + " maxY: samples.maxJ / resolution,", + " };", + " }", + "", + " _getTransform() {", + " const { object } = this;", + " return [object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth()].join(',');", + " }", + "", + " /** @param {string} imageResourceName A heightmap image that is not loaded yet. */", + " _reloadOnceLoaded(imageResourceName) {", + " if (this.loadingHeightmapImage === imageResourceName) return;", + " this.loadingHeightmapImage = imageResourceName;", + " const game = this.object.getRuntimeScene().getGame();", + " game.getImageManager()", + " .loadResource(imageResourceName)", + " .then(() => {", + " if (this.isDisposed || this.loadingHeightmapImage !== imageResourceName) return;", + " this.loadingHeightmapImage = '';", + " if (getLoadedImage(game, imageResourceName)) this.loadFromProperties();", + " })", + " .catch(() => {});", + " }", + "", + " update() {", + " const transform = this._getTransform();", + " if (transform !== this._transform) {", + " this._transform = transform;", + " this.version = ++lastGroundVersion;", + " }", + " this.applyChanges();", + " this.renderer.uniforms.terrainWorldScale.value = getWorldScale(this.object);", + " this._updateWetShore();", + " const layer = this.object.getInstanceContainer().getLayer(this.object.getLayer());", + " this.renderer.updateLevelsOfDetail(layer.getRenderer().getThreeCamera());", + " }", + "", + " _updateWetShore() {", + " const { object } = this;", + " // In the coordinates of the terrain group, like the vertices.", + " const depthScale = AREA_DEPTH / Math.max(object.getDepth(), 0.0001);", + " this.renderer.uniforms.terrainWetShore.value.set(", + " (object._getWetShoreZ() - object.getZ()) * depthScale,", + " Math.max(object._getWetShoreFade(), 0.001) * depthScale,", + " object._getWetShore() ? 1 : 0", + " );", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " getGrounds(this.object.getRuntimeScene()).delete(this);", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this.renderer.dispose();", + " for (const bodyUpdater of this.bodyUpdaters) {", + " bodyUpdater.dispose();", + " }", + " }", + "}", + "", + "/**", + " * @param {gdjs.RuntimeObject} object", + " * @returns {number} The number of scene units by 3D world unit (1 in GDevelop versions before the world scale).", + " */", + "const getWorldScale = (object) => {", + " const scene = object.getRuntimeScene();", + " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", + "};", + "", + "const averageColors = new WeakMap();", + "let white = null;", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " */", + "const getAverageColor = (texture) => {", + " const cachedColor = averageColors.get(texture);", + " if (cachedColor) return cachedColor;", + " const image = texture.image;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", + " const size = 8;", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " context.drawImage(image, 0, 0, size, size);", + " const pixels = context.getImageData(0, 0, size, size).data;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += pixels[index];", + " green += pixels[index + 1];", + " blue += pixels[index + 2];", + " }", + " const count = size * size * 255;", + " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", + " averageColors.set(texture, color);", + " return color;", + "};", + "", + "const svgIcon = (content) =>", + " 'data:image/svg+xml,' +", + " encodeURIComponent('' + content + '');", + "const strokes = 'fill=\"none\" stroke=\"#000\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"';", + "const toolIcons = {", + " Raise: svgIcon(''),", + " Lower: svgIcon(''),", + " Smooth: svgIcon(''),", + " Flatten: svgIcon(''),", + " Size: svgIcon(''),", + " Strength: svgIcon(''),", + " Undo: svgIcon(''),", + " Hole: svgIcon(''),", + " FillHoles: svgIcon(''),", + " Wetness: svgIcon(''),", + "};", + "// Tints for the color brush when the editor has no color picker (older GDevelop versions).", + "const tintPresets = ['#e2c879', '#a5c45a', '#8a6a48', '#c98a62', '#9a9a92', '#ffffff'];", + "", + "/**", + " * The sculpt and paint tools shown in the scene editor when a terrain is", + " * selected. Without the needed editor functions (older GDevelop versions),", + " * nothing is shown: the terrain can still be changed with events.", + " */", + "class TerrainEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Terrain | null} */", + " this.terrain = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.flattenHeight = 0;", + " /** The color of the \"Tint\" brush, as \"#rrggbb\". */", + " this.tintColor = tintPresets[0];", + " this.wetnessPercent = 100;", + " this.lastStrokeTime = 0;", + " /** @type {{data: TerrainData, baseData: TerrainData}[]} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._swatchColor = new THREE.Color();", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') {", + " // Older GDevelop versions: the terrain can only be changed with events.", + " return;", + " }", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const terrain =", + " selectedObjects.length === 1 && selectedObjects[0].__terrain3D ? selectedObjects[0].__terrain3D : null;", + " if (terrain !== this.terrain) {", + " this._endStroke();", + " if (this.terrain) this.terrain.renderer.setBrush(null, 0);", + " this.terrain = terrain;", + " this.undoSteps.length = 0;", + " }", + " if (terrain) editor.showToolbar('Terrain3D', this._getToolbarItems(terrain));", + " const game = editor.getRuntimeGame();", + " if (!terrain || !this.toolName) {", + " if (terrain) terrain.renderer.setBrush(null, 0);", + " return;", + " }", + "", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " terrain.renderer.setBrush(null, 0);", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = terrain.raycastFromCursor(game, this.raycaster, this.ndc);", + " const radius = this._getRadius();", + " terrain.renderer.setBrush(hit, radius);", + "", + " // Older GDevelop versions don't have it.", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(terrain, hit);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(terrain, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.terrain;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), this.terrain.getCellWidth());", + " }", + "", + " _startStroke(terrain, hit) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.flattenHeight = terrain.toScenePosition(hit).z;", + " this.undoSteps.push({ data: copyTerrainData(terrain.data), baseData: terrain.baseData });", + " const maxUndoSteps = Math.max(Math.floor(UNDO_STEPS_SAMPLES / terrain.data.heights.length), 2);", + " while (this.undoSteps.length > maxUndoSteps) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(terrain, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const { x, y } = terrain.toScenePosition(hit);", + " const amount = (this.strengthPercent / 100) * elapsedSeconds;", + " const depth = terrain.object.getDepth();", + " if (this.toolName === 'Raise') terrain.raise(x, y, x, y, radius, amount * depth * 0.5);", + " else if (this.toolName === 'Lower') terrain.raise(x, y, x, y, radius, -amount * depth * 0.5);", + " else if (this.toolName === 'Smooth') terrain.smooth(x, y, x, y, radius, amount * 10);", + " else if (this.toolName === 'Flatten') terrain.flatten(x, y, x, y, radius, this.flattenHeight, amount * 10);", + " else if (this.toolName.startsWith('Paint')) {", + " terrain.paint(x, y, x, y, radius, parseInt(this.toolName.slice(5), 10), amount * 8);", + " } else if (this.toolName === 'Hole') {", + " terrain.makeHole(x, y, x, y, radius);", + " } else if (this.toolName === 'FillHoles') {", + " terrain.fillHoles(x, y, x, y, radius);", + " } else if (this.toolName === 'Tint') {", + " terrain.tint(x, y, x, y, radius, gdjs.rgbOrHexToRGBColor(this.tintColor), amount * 8);", + " } else if (this.toolName === 'Wetness') {", + " terrain.wet(x, y, x, y, radius, this.wetnessPercent / 100, amount * 8);", + " }", + " // Drawn now, as the terrain was updated earlier in this frame.", + " terrain.applyChanges();", + " }", + "", + " _save() {", + " const { terrain, editor } = this;", + " if (!terrain || !editor) return;", + " editor.updateObjectProperties(terrain.object.getName(), { SculptData: terrain.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The relief, the edits or the resolution may have changed since the stroke.", + " if (!this.terrain || !undoStep || undoStep.baseData !== this.terrain.baseData) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.terrain.setData(undoStep.data);", + " this._save();", + " }", + "", + " /** @returns {Array} The settings of the tint or wetness brush, when it's used. */", + " _getColorToolItems() {", + " const { editor } = this;", + " if (this.toolName === 'Tint') {", + " if (editor && typeof editor.isToolbarItemTypeSupported === 'function' && editor.isToolbarItemTypeSupported('color')) {", + " return [", + " {", + " type: 'color',", + " id: 'TintColor',", + " tooltip: 'Color of the tint',", + " value: this.tintColor,", + " onChange: (color) => (this.tintColor = color),", + " },", + " ];", + " }", + " return tintPresets.map((color) => ({", + " type: 'button',", + " id: 'TintPreset' + color,", + " tooltip: color === '#ffffff' ? 'No tint' : 'Tint with this color',", + " color,", + " isActive: this.tintColor === color,", + " onClick: () => (this.tintColor = color),", + " }));", + " }", + " if (this.toolName === 'Wetness') {", + " return [", + " {", + " type: 'slider',", + " id: 'WetnessAmount',", + " tooltip: 'Wetness',", + " iconUrl: toolIcons.Wetness,", + " min: 0,", + " max: 100,", + " value: this.wetnessPercent,", + " onChange: (value) => (this.wetnessPercent = value),", + " },", + " ];", + " }", + " return [];", + " }", + "", + " /**", + " * @param {Terrain} terrain", + " * @returns {Array} The toolbar for the current state (the editor only", + " * updates what changed).", + " */", + " _getToolbarItems(terrain) {", + " const { object } = terrain;", + " const toolButton = (toolName, tooltip, color) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: toolIcons[toolName],", + " color,", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " const layerColors = [object._getLayer1Color(), object._getLayer2Color(), object._getLayer3Color(), object._getLayer4Color()];", + " // Layers are shown with their color, tinting their texture.", + " const swatchColors = layerColors.map((color, index) =>", + " this._swatchColor", + " .set(gdjs.rgbOrHexStringToNumber(color))", + " .multiply(getAverageColor(terrain.renderer.uniforms['terrainLayerMap' + index].value))", + " .getHexString()", + " );", + " return [", + " toolButton('Raise', 'Raise the ground (drag on the terrain)'),", + " toolButton('Lower', 'Lower the ground'),", + " toolButton('Smooth', 'Smooth the ground'),", + " toolButton('Flatten', 'Flatten the ground to the height where the drag starts'),", + " { type: 'divider', id: 'PaintDivider' },", + " ...swatchColors.map((swatchColor, index) =>", + " toolButton('Paint' + (index + 1), 'Paint layer ' + (index + 1), '#' + swatchColor)", + " ),", + " toolButton('Hole', 'Make a hole, for the entrance of a tunnel or a cave'),", + " toolButton('FillHoles', 'Fill holes, with the layers of the ground around them'),", + " { type: 'divider', id: 'ColorDivider' },", + " toolButton('Tint', 'Tint the ground (white removes the tint)', this.tintColor),", + " toolButton('Wetness', 'Make the ground wet, or dry with a wetness of 0'),", + " ...this._getColorToolItems(),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " { type: 'button', id: 'Undo', tooltip: 'Undo the last stroke on this terrain', iconUrl: toolIcons.Undo, onClick: () => this._undo() },", + " ];", + " }", + "}", + "", + "const editorTools = new TerrainEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrain3DExtension = {", + " Terrain,", + " // Used by the terrain grass and the scattered models.", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " svgIcon,", + " toolIcons,", + " // Exposed for tests.", + " TerrainBodyUpdater,", + " TerrainData,", + " SampleRectangle,", + " brushes,", + " edits,", + " codec,", + " relief,", + "};" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define grass helper classes JavaScript code.", + "fullName": "Define grass helper classes", + "functionType": "Action", + "name": "DefineGrassHelperClasses", + "private": true, + "sentence": "Define grass helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainGrassExtension) {", + " return;", + "}", + "// Blades grow on the grounds of the scene: the 3D terrains (see `getGrounds`", + "// in the terrain helper).", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 1000;", + "const AREA_DEPTH = 40;", + "const CHUNK_SIZE = 500;", + "const MAX_BENDING_OBJECTS = 8;", + "", + "/**", + " * A blade: a thin, tapered strip. Its width and height are 1: blades are", + " * scaled by the shader.", + " */", + "const createBladeGeometry = () => {", + " const halfWidths = [0.5, 0.42, 0.28, 0];", + " const heights = [0, 0.35, 0.7, 1];", + " const positions = [];", + " halfWidths.forEach((halfWidth, level) => {", + " positions.push(-halfWidth, 0, heights[level]);", + " if (halfWidth > 0) positions.push(halfWidth, 0, heights[level]);", + " });", + " const indices = [0, 1, 2, 1, 3, 2, 2, 3, 4, 3, 5, 4, 4, 5, 6];", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));", + " geometry.setAttribute('normal', new THREE.Float32BufferAttribute(new Array(positions.length).fill(0), 3));", + " geometry.setIndex(indices);", + " return geometry;", + "};", + "", + "const vertexShaderDeclarations = `", + "attribute vec4 grassRoot;", + "attribute vec2 grassShape;", + "// The tint of the ground at the root (linear, from 0 to 1).", + "attribute vec3 grassGroundTint;", + "uniform mat3 grassWorldToLocal;", + "uniform float grassWorldScale;", + "uniform float grassBladeWidth;", + "uniform float grassTime;", + "uniform float grassWindStrength;", + "uniform float grassWindSpeed;", + "uniform vec4 grassBenders[${MAX_BENDING_OBJECTS}];", + "uniform vec3 grassBaseColor;", + "uniform vec3 grassTipColor;", + "varying vec3 vGrassColor;", + "`;", + "const vertexShaderPosition = `", + "// Blades are shaped in scene units (with Y flipped like the 3D world), then", + "// moved back in the (scaled) object space.", + "float bladeHeight = position.z;", + "float grassAngle = grassRoot.w;", + "float bladeWidth = position.x * grassBladeWidth;", + "vec3 blade = vec3(", + " bladeWidth * cos(grassAngle),", + " bladeWidth * sin(grassAngle),", + " bladeHeight * grassShape.x", + ");", + "vec3 rootWorld = (modelMatrix * vec4(grassRoot.xyz, 1.0)).xyz * grassWorldScale;", + "// Tips bend more than the base.", + "float bendFactor = bladeHeight * bladeHeight * grassShape.x;", + "float gust = sin(grassTime * grassWindSpeed + rootWorld.x * 0.013 + rootWorld.y * 0.011);", + "float flutter = sin(grassTime * grassWindSpeed * 2.7 + grassShape.y * 40.0) * 0.3;", + "blade.xy += vec2(0.8, 0.5) * (gust + flutter + 0.6) * grassWindStrength * 0.35 * bendFactor;", + "for (int i = 0; i < ${MAX_BENDING_OBJECTS}; i++) {", + " vec4 bender = grassBenders[i];", + " if (bender.z <= 0.0) continue;", + " vec2 away = rootWorld.xy - bender.xy;", + " float distanceToBender = length(away);", + " float push = 1.0 - smoothstep(bender.z * 0.3, bender.z, distanceToBender);", + " if (push > 0.0) {", + " blade.xy += normalize(away + vec2(0.001)) * push * bendFactor * 0.9;", + " blade.z *= 1.0 - push * 0.5;", + " }", + "}", + "vec3 transformed = grassRoot.xyz + grassWorldToLocal * (blade / grassWorldScale);", + "vGrassColor = mix(grassBaseColor, grassTipColor, bladeHeight) * (0.85 + 0.3 * grassShape.y) * grassGroundTint;", + "`;", + "const vertexShaderNormal = `", + "// Blades are lit like the ground below them.", + "transformedNormal = normalize((viewMatrix * vec4(0.0, 0.0, 1.0, 0.0)).xyz);", + "`;", + "const fragmentShaderDeclarations = `", + "varying vec3 vGrassColor;", + "`;", + "const fragmentShaderColor = `", + "diffuseColor.rgb *= vGrassColor;", + "`;", + "// Both faces of blades are lit like the ground (not flipped for back faces).", + "const fragmentShaderNormal = `", + "#include ", + "normal = normalize(vNormal);", + "nonPerturbedNormal = normal;", + "`;", + "", + "const { getWorldScale, patchShaderCode, createRandom, findHighestGround, GroundPlacement } = gdjs.__terrain3DExtension;", + "", + "/**", + " * The grass of a terrain grass object: blades drawn with GPU instancing, in chunks", + " * that are hidden when off-screen and thinned out with the distance. They grow", + " * on the grounds below, like 3D terrains (only where a given layer is painted).", + " */", + "class Grass {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " this.bladeGeometry = createBladeGeometry();", + " /** @type {Array<{mesh: THREE.Mesh, blades: number, center: THREE.Vector3}>} */", + " this.chunks = [];", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this._groundAtBlade = { ground: null, z: 0 };", + " this.uniforms = {", + " grassWorldToLocal: { value: new THREE.Matrix3() },", + " // Scene units by 3D world unit.", + " grassWorldScale: { value: 1 },", + " grassBladeWidth: { value: 1 },", + " grassTime: { value: 0 },", + " grassWindStrength: { value: 1 },", + " grassWindSpeed: { value: 1 },", + " grassBenders: { value: Array.from({ length: MAX_BENDING_OBJECTS }, () => new THREE.Vector4()) },", + " grassBaseColor: { value: new THREE.Color() },", + " grassTipColor: { value: new THREE.Color() },", + " };", + " this.material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0, side: THREE.DoubleSide });", + " this.material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, this.uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + vertexShaderDeclarations],", + " ['#include ', vertexShaderPosition],", + " ['#include ', '#include \\n' + vertexShaderNormal],", + " ], 'TerrainGrass');", + " shader.fragmentShader = patchShaderCode(shader.fragmentShader, [", + " ['#include ', '#include \\n' + fragmentShaderDeclarations],", + " ['#include ', '#include \\n' + fragmentShaderColor],", + " ['#include ', fragmentShaderNormal],", + " ], 'TerrainGrass');", + " };", + " this.material.customProgramCacheKey = () => 'TerrainGrass';", + "", + " this._matrix = new THREE.Matrix4();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " this._scale = new THREE.Vector3();", + " this.updateFromProperties();", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " this.uniforms.grassBaseColor.value.set(gdjs.rgbOrHexStringToNumber(object._getBaseColor()));", + " this.uniforms.grassTipColor.value.set(gdjs.rgbOrHexStringToNumber(object._getTipColor()));", + " this.uniforms.grassWindStrength.value = object._getWindStrength();", + " this.uniforms.grassWindSpeed.value = object._getWindSpeed();", + " this.uniforms.grassBladeWidth.value = Math.max(object._getBladeWidth(), 0);", + " this.material.needsUpdate = true;", + " this.placement.placeAgain();", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getBladeHeight(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getSeed(),", + " ].join('|');", + " }", + "", + " /** Place the blades again, for example after the ground or the object changed. */", + " rebuild() {", + " const grounds = Array.from(this.placement.grounds);", + " for (const chunk of this.chunks) {", + " chunk.mesh.removeFromParent();", + " chunk.mesh.geometry.dispose();", + " }", + " this.chunks.length = 0;", + "", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const scaleX = width / AREA_SIZE;", + " const scaleY = height / AREA_SIZE;", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const bladesPerChunk = Math.round((Math.max(object._getDensity(), 0) * CHUNK_SIZE * CHUNK_SIZE) / 10000);", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " const maxSlope = object._getMaxSlope();", + " const chunksX = Math.max(Math.ceil(width / CHUNK_SIZE), 1);", + " const chunksY = Math.max(Math.ceil(height / CHUNK_SIZE), 1);", + " const nextRandom = createRandom(object._getSeed() * 7919 + 1);", + " const bladeHeight = Math.max(object._getBladeHeight(), 0);", + "", + " for (let chunkY = 0; chunkY < chunksY; chunkY++) {", + " for (let chunkX = 0; chunkX < chunksX; chunkX++) {", + " const roots = new Float32Array(bladesPerChunk * 4);", + " const shapes = new Float32Array(bladesPerChunk * 2);", + " const groundTints = new Uint8Array(bladesPerChunk * 3).fill(255);", + " let blades = 0;", + " let minZ = Infinity;", + " let maxZ = -Infinity;", + " for (let attempt = 0; attempt < bladesPerChunk; attempt++) {", + " // In scene units, relative to the object.", + " const x = (chunkX + nextRandom()) * CHUNK_SIZE;", + " const y = (chunkY + nextRandom()) * CHUNK_SIZE;", + " const angle = nextRandom() * Math.PI * 2;", + " const heightFactor = 0.6 + 0.8 * nextRandom();", + " const tint = nextRandom();", + " const growth = nextRandom();", + " if (x > width || y > height) continue;", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtBlade);", + " const groundZ = ground ? z : object.getZ();", + " if (ground) {", + " if (groundLayer > 0 && growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) continue;", + " if (ground.getSlopeAt(sceneX, sceneY) > maxSlope) continue;", + " if (typeof ground.getTintAt === 'function') {", + " const tint = ground.getTintAt(sceneX, sceneY);", + " for (let channel = 0; channel < 3; channel++) {", + " groundTints[blades * 3 + channel] = Math.round(255 * Math.pow(tint[channel] / 255, 2.2));", + " }", + " }", + " }", + " const localZ = (groundZ - object.getZ()) / scaleZ;", + " roots[blades * 4] = x / scaleX;", + " roots[blades * 4 + 1] = y / scaleY;", + " roots[blades * 4 + 2] = localZ;", + " roots[blades * 4 + 3] = angle;", + " shapes[blades * 2] = heightFactor * bladeHeight;", + " shapes[blades * 2 + 1] = tint;", + " minZ = Math.min(minZ, localZ);", + " maxZ = Math.max(maxZ, localZ);", + " blades++;", + " }", + " if (blades === 0) continue;", + "", + " const geometry = new THREE.InstancedBufferGeometry();", + " geometry.index = this.bladeGeometry.index;", + " geometry.setAttribute('position', this.bladeGeometry.attributes.position);", + " geometry.setAttribute('normal', this.bladeGeometry.attributes.normal);", + " geometry.setAttribute('grassRoot', new THREE.InstancedBufferAttribute(roots.subarray(0, blades * 4), 4));", + " geometry.setAttribute('grassShape', new THREE.InstancedBufferAttribute(shapes.subarray(0, blades * 2), 2));", + " geometry.setAttribute('grassGroundTint', new THREE.InstancedBufferAttribute(groundTints.subarray(0, blades * 3), 3, true));", + " geometry.instanceCount = blades;", + " // The furthest tips can go with the wind and the bending objects (see the shader).", + " const maxBladeHeight = bladeHeight * 1.4;", + " const lean =", + " (0.35 * 1.9 * 0.943 * Math.max(object._getWindStrength(), 0) + 0.9) * maxBladeHeight +", + " Math.max(object._getBladeWidth(), 0) / 2;", + " const leanX = lean / scaleX;", + " const leanY = lean / scaleY;", + " geometry.boundingBox = new THREE.Box3(", + " new THREE.Vector3((chunkX * CHUNK_SIZE) / scaleX - leanX, (chunkY * CHUNK_SIZE) / scaleY - leanY, minZ),", + " new THREE.Vector3(", + " Math.min((chunkX + 1) * CHUNK_SIZE, width) / scaleX + leanX,", + " Math.min((chunkY + 1) * CHUNK_SIZE, height) / scaleY + leanY,", + " maxZ + (bladeHeight * 1.4) / scaleZ", + " )", + " );", + " geometry.boundingSphere = geometry.boundingBox.getBoundingSphere(new THREE.Sphere());", + " const mesh = new THREE.Mesh(geometry, this.material);", + " mesh.receiveShadow = true;", + " // Raycasts would only test one blade: the selection plane is used instead.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " this.chunks.push({ mesh, blades, center: geometry.boundingSphere.center.clone() });", + " }", + " }", + " }", + "", + " _updateBendingObjects() {", + " const benders = this.uniforms.grassBenders.value;", + " const objectName = this.object._getBendingObject();", + " const bendingObjects = objectName ? this.object.getInstanceContainer().getObjects(objectName) || [] : [];", + " for (let index = 0; index < MAX_BENDING_OBJECTS; index++) {", + " const bendingObject = bendingObjects[index];", + " if (!bendingObject) {", + " benders[index].set(0, 0, 0, 0);", + " continue;", + " }", + " // Blades are pushed in the 3D scene, which is flipped on Y.", + " const radius = Math.max(bendingObject.getWidth(), bendingObject.getHeight()) * 1.2;", + " benders[index].set(bendingObject.getCenterXInScene(), -bendingObject.getCenterYInScene(), radius, 0);", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {number} time In seconds, the same for all grass objects.", + " */", + " update(elapsedSeconds, time, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + "", + " this.uniforms.grassTime.value = time;", + " this.uniforms.grassWorldScale.value = getWorldScale(this.object);", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this.uniforms.grassWorldToLocal.value.setFromMatrix4(this._matrix.copy(this.group.matrixWorld).invert());", + " this._updateBendingObjects();", + " if (!camera) return;", + "", + " // Far chunks are hidden, and thinned out before (in 3D world units).", + " const fadeDistance = Math.max(this.object._getFadeDistance(), 1) / getWorldScale(this.object);", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const density = gdjs.evtTools.common.clamp((fadeDistance - distance) / (fadeDistance * 0.5), 0, 1);", + " chunk.mesh.visible = density > 0;", + " chunk.mesh.geometry.instanceCount = Math.ceil(chunk.blades * density);", + " }", + " }", + "", + " dispose() {", + " for (const chunk of this.chunks) {", + " chunk.mesh.geometry.dispose();", + " }", + " this.bladeGeometry.dispose();", + " this.material.dispose();", + " this.group.removeFromParent();", + " }", + "}", + "", + "gdjs.__terrainGrassExtension = { Grass };" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + }, + { + "description": "Define scattered models helper classes JavaScript code.", + "fullName": "Define scattered models helper classes", + "functionType": "Action", + "name": "DefineScatterHelperClasses", + "private": true, + "sentence": "Define scattered models helper classes JavaScript code", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "if (gdjs.__terrainScatterExtension) {", + " return;", + "}", + "// Copies grow on the grounds of the scene, like the terrain grass (see", + "// `getGrounds` in the terrain helper).", + "", + "const {", + " getWorldScale,", + " getGrounds,", + " patchShaderCode,", + " createRandom,", + " findHighestGround,", + " GroundPlacement,", + " SampleRectangle,", + " brushes,", + " codec,", + " svgIcon,", + " toolIcons,", + "} = gdjs.__terrain3DExtension;", + "", + "// Size of the object inner area: instances are scaled from it.", + "const AREA_SIZE = 2000;", + "const AREA_DEPTH = 200;", + "// The painted density is stored in a grid of this many cells on each side,", + "// whatever the size of the object.", + "const MASK_RESOLUTION = 256;", + "const MASK_FORMAT_VERSION = '1';", + "// Copies are hidden in chunks: big chunks mean fewer draw calls, small ones", + "// hide more copies out of the screen.", + "const MIN_CHUNK_SIZE = 500;", + "const MAX_CHUNK_SIZE = 2000;", + "// Copies shrink to nothing over this part of the draw distance, instead of popping out.", + "const FADE_PART = 0.15;", + "const MAX_COPIES = 200000;", + "// Prisms of the trunk collisions.", + "const TRUNK_SIDES = 6;", + "", + "const clamp01 = (value) => (value < 0 ? 0 : value > 1 ? 1 : value);", + "", + "/**", + " * @returns {number} A number for a cell of the copies grid, changing with the seed.", + " */", + "const hashCell = (seed, i, j) => {", + " let h = Math.imul(i, 374761393) + Math.imul(j, 668265263) + Math.imul(seed, 982451653);", + " h = Math.imul(h ^ (h >>> 13), 1274126177);", + " return (h ^ (h >>> 16)) >>> 0;", + "};", + "", + "/**", + " * How dense copies are, from 0 to 1, in a grid covering the object: painted", + " * with the editor brushes, the edits or events.", + " */", + "class DensityMask {", + " /** @param {number} fillValue From 0 to 255. */", + " constructor(fillValue) {", + " // `resolution` and `size` let terrain brushes paint it.", + " this.resolution = MASK_RESOLUTION;", + " this.size = MASK_RESOLUTION + 1;", + " this.values = new Uint8Array(this.size * this.size).fill(fillValue);", + " }", + "", + " /**", + " * @param {number} u From 0 to 1, along the object width.", + " * @param {number} v From 0 to 1, along the object height.", + " * @returns {number} The density, from 0 to 1, interpolated between samples.", + " */", + " sample(u, v) {", + " const x = clamp01(u) * this.resolution;", + " const y = clamp01(v) * this.resolution;", + " const i = Math.min(Math.floor(x), this.resolution - 1);", + " const j = Math.min(Math.floor(y), this.resolution - 1);", + " const fx = x - i;", + " const fy = y - j;", + " const value = (i, j) => this.values[j * this.size + i];", + " const top = value(i, j) + fx * (value(i + 1, j) - value(i, j));", + " const bottom = value(i, j + 1) + fx * (value(i + 1, j + 1) - value(i, j + 1));", + " return (top + fy * (bottom - top)) / 255;", + " }", + "", + " /**", + " * Bring the density towards a target around a segment: fully up to 70%", + " * of the radius, then fading out (forests have dense centers and soft edges).", + " * @param {{cellWidth: number, cellHeight: number, ax: number, ay: number, bx: number, by: number, radius: number}} stroke", + " * @param {number} density The target, from 0 to 1.", + " * @param {number} strength From 0 to 1.", + " * @param {SampleRectangle} changedSamples", + " */", + " paint(stroke, density, strength, changedSamples) {", + " const { values } = this;", + " const target = Math.round(clamp01(density) * 255);", + " brushes.forEachSample(", + " this,", + " stroke,", + " (index, falloff) => {", + " // The falloff of terrain brushes is (1 - distance² / radius²)².", + " const weight = clamp01(2 * Math.sqrt(falloff));", + " // Rounded towards the target, so that light strokes still paint.", + " const change = (target - values[index]) * clamp01(weight * strength);", + " values[index] += change > 0 ? Math.ceil(change) : Math.floor(change);", + " },", + " changedSamples", + " );", + " }", + "", + " /** @returns {DensityMask} */", + " clone() {", + " const mask = new DensityMask(0);", + " mask.values.set(this.values);", + " return mask;", + " }", + "}", + "", + "/**", + " * Edits written in the Edits property: a JSON list of brush strokes, like", + " * `[{\"tool\": \"add\", \"x\": 0.5, \"y\": 0.5, \"radius\": 0.2}]`. Positions and", + " * radius are fractions of the object size, like the terrain edits.", + " */", + "const applyEdits = (mask, text) => {", + " if (!text.trim()) return;", + " let editList;", + " try {", + " editList = JSON.parse(text);", + " } catch (error) {", + " console.warn('The edits of scattered models are not valid JSON: ' + error.message);", + " return;", + " }", + " if (!Array.isArray(editList)) {", + " console.warn('The edits of scattered models must be a JSON list (like [{\"tool\": \"add\", ...}]).');", + " return;", + " }", + " const numberOr = (value, defaultValue) => (typeof value === 'number' && isFinite(value) ? value : defaultValue);", + " const changedSamples = new SampleRectangle();", + " for (const edit of editList) {", + " if (!edit || typeof edit !== 'object') continue;", + " const x = numberOr(edit.x, 0.5);", + " const y = numberOr(edit.y, 0.5);", + " const stroke = {", + " cellWidth: 1 / mask.resolution,", + " cellHeight: 1 / mask.resolution,", + " ax: x,", + " ay: y,", + " bx: numberOr(edit.toX, x),", + " by: numberOr(edit.toY, y),", + " radius: numberOr(edit.radius, 0.1),", + " };", + " const strength = clamp01(numberOr(edit.strength, 1));", + " if (edit.tool === 'add') {", + " mask.paint(stroke, numberOr(edit.density, 1), strength, changedSamples);", + " } else if (edit.tool === 'erase') {", + " mask.paint(stroke, 0, strength, changedSamples);", + " } else {", + " console.warn('Unknown tool in the edits of scattered models: \"' + edit.tool + '\" (use add or erase).');", + " }", + " }", + "};", + "", + "/**", + " * The density painted in the editor, stored as its difference with the", + " * density from the properties (the coverage and the edits), like the terrain", + " * sculpt data.", + " */", + "const maskCodec = {", + " /**", + " * @param {DensityMask} mask", + " * @param {DensityMask} baseMask", + " */", + " encode(mask, baseMask) {", + " const changes = new Int32Array(mask.values.length);", + " let hasChanges = false;", + " for (let index = 0; index < changes.length; index++) {", + " changes[index] = mask.values[index] - baseMask.values[index];", + " if (changes[index] !== 0) hasChanges = true;", + " }", + " if (!hasChanges) return '';", + " return MASK_FORMAT_VERSION + ';' + MASK_RESOLUTION + ';' + codec.encodeGrids([changes], mask.size);", + " },", + "", + " /**", + " * @param {string} text", + " * @param {DensityMask} baseMask", + " * @returns {DensityMask | null} null if the text is empty or not valid.", + " */", + " decode(text, baseMask) {", + " if (!text) return null;", + " const parts = text.split(';');", + " if (parts[0] !== MASK_FORMAT_VERSION || parseInt(parts[1], 10) !== MASK_RESOLUTION) return null;", + " try {", + " const mask = baseMask.clone();", + " const [changes] = codec.decodeGrids(parts[2], mask.size, 1);", + " for (let index = 0; index < changes.length; index++) {", + " // The base may have changed since the data was saved.", + " mask.values[index] = Math.min(Math.max(mask.values[index] + changes[index], 0), 255);", + " }", + " return mask;", + " } catch (error) {", + " console.error('The painted data of scattered models could not be read:', error);", + " return null;", + " }", + " },", + "};", + "", + "const fadeShaderDeclarations = `", + "uniform float scatterDrawDistance;", + "`;", + "// Instance matrices are applied after this: copies shrink towards their base.", + "const fadeShaderCode = `", + "#ifdef USE_INSTANCING", + "vec3 scatterCopyPosition = (modelMatrix * instanceMatrix * vec4(0.0, 0.0, 0.0, 1.0)).xyz;", + "transformed *= clamp(", + " (scatterDrawDistance - distance(scatterCopyPosition, cameraPosition)) / (scatterDrawDistance * ${FADE_PART}),", + " 0.0,", + " 1.0", + ");", + "#endif", + "`;", + "", + "const flipTriangles = (geometry) => {", + " const index = geometry.index;", + " for (let offset = 0; offset + 2 < index.count; offset += 3) {", + " const second = index.getX(offset + 1);", + " index.setX(offset + 1, index.getX(offset + 2));", + " index.setX(offset + 2, second);", + " }", + "};", + "", + "/**", + " * The parts of a model, ready to be drawn with instancing: each glTF", + " * primitive with its material. Geometries are moved so that the model base", + " * is at the origin, its height is 1 and it stands along Z (like 3D model", + " * objects with a 90° rotation around X).", + " * @param {THREE.Object3D} modelScene", + " * @param {object} uniforms Uniforms added to the materials.", + " * @returns {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}}", + " */", + "const createModelParts = (modelScene, uniforms) => {", + " modelScene.updateMatrixWorld(true);", + " const rootInverse = modelScene.matrixWorld.clone().invert();", + " const standUp = new THREE.Matrix4().makeRotationX(Math.PI / 2);", + " /** @type {Array<{mesh: THREE.Mesh, matrix: THREE.Matrix4}>} */", + " const meshes = [];", + " const box = new THREE.Box3();", + " modelScene.traverse((node) => {", + " if (!node.isMesh || !node.geometry || !node.geometry.attributes.position) return;", + " const matrix = standUp.clone().multiply(rootInverse).multiply(node.matrixWorld);", + " if (!node.geometry.boundingBox) node.geometry.computeBoundingBox();", + " box.union(node.geometry.boundingBox.clone().applyMatrix4(matrix));", + " meshes.push({ mesh: node, matrix });", + " });", + " if (box.isEmpty()) return { parts: [], width: 0, depth: 0 };", + "", + " const height = Math.max(box.max.z - box.min.z, 0.000001);", + " // The Y axis of the scene goes down: the model is flipped, like 3D model objects.", + " const normalization = new THREE.Matrix4()", + " .makeScale(1 / height, -1 / height, 1 / height)", + " .multiply(", + " new THREE.Matrix4().makeTranslation(", + " -(box.min.x + box.max.x) / 2,", + " -(box.min.y + box.max.y) / 2,", + " -box.min.z", + " )", + " );", + " const parts = meshes.map(({ mesh, matrix }) => {", + " let geometry = mesh.geometry.clone();", + " if (!geometry.index) {", + " const indices = Array.from({ length: geometry.attributes.position.count }, (_, index) => index);", + " geometry.setIndex(indices);", + " }", + " geometry.applyMatrix4(normalization.clone().multiply(matrix));", + " // The flip turned the faces inside out.", + " flipTriangles(geometry);", + " geometry.computeBoundingSphere();", + " geometry.computeBoundingBox();", + " const patchMaterial = (originalMaterial) => {", + " const material = originalMaterial.clone();", + " // Like 3D model objects (\"Standard without metalness\"), which look better without an environment map.", + " if (material.metalness) material.metalness = 0;", + " material.onBeforeCompile = (shader) => {", + " Object.assign(shader.uniforms, uniforms);", + " shader.vertexShader = patchShaderCode(shader.vertexShader, [", + " ['#include ', '#include \\n' + fadeShaderDeclarations],", + " ['#include ', '#include \\n' + fadeShaderCode],", + " ], 'ScatteredModels');", + " };", + " material.customProgramCacheKey = () => 'ScatteredModels';", + " return material;", + " };", + " const material = Array.isArray(mesh.material) ? mesh.material.map(patchMaterial) : patchMaterial(mesh.material);", + " return { geometry, material };", + " });", + " return {", + " parts,", + " width: (box.max.x - box.min.x) / height,", + " depth: (box.max.y - box.min.y) / height,", + " };", + "};", + "", + "/**", + " * A copy of the model: its base position in the scene, its scale (the", + " * height of the copy) and the key of its cell in the grid of copies.", + " * @typedef {{x: number, y: number, z: number, angle: number, height: number, key: number}} Copy", + " */", + "", + "/**", + " * The scattered models of an object: copies of a 3D model placed on the", + " * grounds of the scene, drawn with GPU instancing in chunks that are hidden", + " * when far or off-screen.", + " */", + "class Scatter {", + " /** @param {gdjs.CustomRuntimeObject3D} object */", + " constructor(object) {", + " this.object = object;", + " this.group = new THREE.Group();", + " object.get3DRendererObject().add(this.group);", + " /** @type {Array<{firstCellI: number, firstCellJ: number, meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}>} */", + " this.chunks = [];", + " /**", + " * The grid of copies: one copy at most in each cell, cells grouped in chunks.", + " * @type {{spacing: number, cellsPerChunk: number, cellsX: number, cellsY: number} | null}", + " */", + " this.grid = null;", + " this.placement = new GroundPlacement(object.getRuntimeScene());", + " this.uniforms = {", + " // In 3D world units.", + " scatterDrawDistance: { value: 1 },", + " };", + " /** @type {{parts: Array<{geometry: THREE.BufferGeometry, material: THREE.Material | THREE.Material[]}>, width: number, depth: number}} */", + " this.model = { parts: [], width: 0, depth: 0 };", + " this.modelResourceName = '';", + " this.loadingModelResourceName = '';", + " /**", + " * Copies removed by events (for example, cut trees), by key.", + " * @type {Map}", + " */", + " this.removedCopies = new Map();", + " /** Increased each time copies change, for the collisions. */", + " this.version = 0;", + " this.isDisposed = false;", + " /** The last value of the painted data property read or saved. */", + " this.paintData = '';", + " /**", + " * Values saved by the editor tools: the editor sends them back with a", + " * hot-reload, possibly after newer ones were saved.", + " * @type {string[]}", + " */", + " this.savedPaintData = [];", + " this.maskSource = '';", + " /** @type {DensityMask} */", + " this.baseMask = new DensityMask(255);", + " /** @type {DensityMask} */", + " this.mask = this.baseMask;", + " this.changedSamples = new SampleRectangle();", + " this._stroke = { cellWidth: 1, cellHeight: 1, ax: 0, ay: 0, bx: 0, by: 0, radius: 0 };", + " this._groundAtCopy = { ground: null, z: 0 };", + " this._matrix = new THREE.Matrix4();", + " this._raycastSphere = new THREE.Sphere();", + " this._raycastRay = new THREE.Ray();", + " this._raycastBox = new THREE.Box3();", + " this._raycastInverseMatrix = new THREE.Matrix4();", + " this._raycastScale = new THREE.Vector3();", + " /** Placed on a copy to test the triangles of the model. */", + " this._raycastMesh = new THREE.Mesh();", + " /** @type {THREE.Intersection[]} */", + " this._raycastHits = [];", + " this._color = new THREE.Color();", + " this._tint = new THREE.Color();", + " this._cameraPosition = new THREE.Vector3();", + " this._chunkPosition = new THREE.Vector3();", + " /**", + " * Trunks, for the 3D physics behavior and navigation meshes. Always given,", + " * empty without trunk collisions: otherwise these behaviors would use the", + " * object box, covering the whole area.", + " * @type {gdjs.Surface}", + " */", + " this.surface = {", + " getVersion: () => this.version,", + " getChangedArea: () => null,", + " getTriangles: () => this._getTrunkTriangles(),", + " getHeightField: () => null,", + " };", + " /** The trunk collision properties, changing the surface. */", + " this.trunkKey = '';", + " this.loadMaskFromProperties();", + " this.updateFromProperties();", + " // Before the behaviors create their shapes.", + " this._updateSurface();", + " }", + "", + " _getMaskSource() {", + " return this.object._getCoverage() + '|' + this.object._getEdits();", + " }", + "", + " loadMaskFromProperties() {", + " const { object } = this;", + " this.maskSource = this._getMaskSource();", + " this.paintData = object._getPaintData();", + " this.baseMask = new DensityMask(object._getCoverage() === 'Painted' ? 0 : 255);", + " applyEdits(this.baseMask, object._getEdits());", + " this.mask = maskCodec.decode(this.paintData, this.baseMask) || this.baseMask.clone();", + " this.placement.placeAgain();", + " }", + "", + " onHotReloading() {", + " const paintData = this.object._getPaintData();", + " const savedIndex = this.savedPaintData.indexOf(paintData);", + " if (savedIndex !== -1 && this._getMaskSource() === this.maskSource) {", + " // The object already has this data, or newer changes.", + " this.savedPaintData.splice(0, savedIndex + 1);", + " } else if (paintData !== this.paintData || this._getMaskSource() !== this.maskSource) {", + " this.savedPaintData.length = 0;", + " this.loadMaskFromProperties();", + " }", + " this.updateFromProperties();", + " }", + "", + " /** @returns {string} The data to save in the painted data property. */", + " save() {", + " this.paintData = maskCodec.encode(this.mask, this.baseMask);", + " this.savedPaintData.push(this.paintData);", + " return this.paintData;", + " }", + "", + " updateFromProperties() {", + " const { object } = this;", + " const modelResourceName = object._getModel();", + " if (modelResourceName !== this.modelResourceName) {", + " this.modelResourceName = modelResourceName;", + " this._loadModel();", + " }", + " this.placement.placeAgain();", + " }", + "", + " _disposeModel() {", + " for (const part of this.model.parts) {", + " part.geometry.dispose();", + " for (const material of Array.isArray(part.material) ? part.material : [part.material]) {", + " material.dispose();", + " }", + " }", + " this.model = { parts: [], width: 0, depth: 0 };", + " }", + "", + " _loadModel() {", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " const resourceName = this.modelResourceName;", + " if (!resourceName) return;", + " const game = this.object.getRuntimeScene().getGame();", + " const modelManager = game.getModel3DManager();", + " const gltf = modelManager.getModel(resourceName);", + " if (gltf === modelManager._invalidModel) {", + " // Not loaded yet, for example a model just chosen in the editor.", + " if (this.loadingModelResourceName === resourceName) return;", + " this.loadingModelResourceName = resourceName;", + " game.getResourceLoader()", + " .loadResource(resourceName)", + " .then(() => {", + " if (this.isDisposed || this.modelResourceName !== resourceName) return;", + " this.loadingModelResourceName = '';", + " if (modelManager.getModel(resourceName) !== modelManager._invalidModel) {", + " this._loadModel();", + " this.placement.placeAgain();", + " }", + " })", + " .catch(() => {});", + " return;", + " }", + " this.model = createModelParts(gltf.scene, this.uniforms);", + " }", + "", + " _getPlacementKey() {", + " const { object } = this;", + " return [", + " object.getX(), object.getY(), object.getZ(), object.getWidth(), object.getHeight(), object.getDepth(),", + " object._getDensity(), object._getSize(), object._getMinScale(), object._getMaxScale(),", + " object._getRandomRotation(), object._getRandomTint(), object._getGroundLayer(), object._getMaxSlope(),", + " object._getMinGroundZ(), object._getMaxGroundZ(), object._getSeed(), object._getDrawDistance(),", + " object._getCastShadow(), object._getReceiveShadow(), this.model.parts.length,", + " ].join('|');", + " }", + "", + " _getChunkSize() {", + " return Math.min(Math.max(this.object._getDrawDistance() / 4, MIN_CHUNK_SIZE), MAX_CHUNK_SIZE);", + " }", + "", + " /** @returns {number} The distance between copies (one copy per cell of this size at most). */", + " _getSpacing() {", + " const { object } = this;", + " const density = Math.max(object._getDensity(), 0);", + " if (density <= 0) return 0;", + " const spacing = 100 / Math.sqrt(density);", + " // Too many cells would freeze the game: the density is lowered.", + " const cellCount = (object.getWidth() / spacing) * (object.getHeight() / spacing);", + " return cellCount > MAX_COPIES ? spacing * Math.sqrt(cellCount / MAX_COPIES) : spacing;", + " }", + "", + " /**", + " * Find the copy of a cell of the grid, if there is one.", + " * @returns {Copy | null}", + " */", + " _placeCopy(cellI, cellJ, spacing, grounds) {", + " const { object } = this;", + " const width = object.getWidth();", + " const height = object.getHeight();", + " const nextRandom = createRandom(hashCell(Math.floor(object._getSeed()), cellI, cellJ));", + " // Always drawn in the same order, so that a copy stays the same when properties change.", + " const x = (cellI + nextRandom()) * spacing;", + " const y = (cellJ + nextRandom()) * spacing;", + " const presence = nextRandom();", + " const growth = nextRandom();", + " const scaleFactor = nextRandom();", + " const angle = nextRandom() * Math.PI * 2;", + " if (x > width || y > height) return null;", + " if (presence >= this.mask.sample(x / width, y / height)) return null;", + " const key = cellJ * 65536 + cellI;", + " if (this.removedCopies.has(key)) return null;", + "", + " const sceneX = object.getX() + x;", + " const sceneY = object.getY() + y;", + " const { ground, z } = findHighestGround(grounds, sceneX, sceneY, this._groundAtCopy);", + " const groundZ = ground ? z : object.getZ();", + " if (groundZ < object._getMinGroundZ() || groundZ > object._getMaxGroundZ()) return null;", + " const copyHeight =", + " Math.max(object._getSize(), 0) *", + " (object._getMinScale() + (object._getMaxScale() - object._getMinScale()) * scaleFactor);", + " if (ground) {", + " if (ground.getSlopeAt(sceneX, sceneY) > object._getMaxSlope()) return null;", + " const groundLayer = parseInt(object._getGroundLayer(), 10) || 0;", + " if (groundLayer > 0) {", + " if (growth > ground.getLayerWeightAt(sceneX, sceneY, groundLayer)) return null;", + " // Copies don't stand at the border of their layer, so that trees don't cover roads.", + " const margin = (copyHeight * Math.max(this.model.width, this.model.depth)) / 4;", + " for (const [offsetX, offsetY] of [[margin, 0], [-margin, 0], [0, margin], [0, -margin]]) {", + " if (ground.getLayerWeightAt(sceneX + offsetX, sceneY + offsetY, groundLayer) < 0.5) return null;", + " }", + " }", + " }", + " return {", + " x: sceneX,", + " y: sceneY,", + " z: groundZ,", + " angle: object._getRandomRotation() ? angle : 0,", + " height: copyHeight,", + " key,", + " };", + " }", + "", + " _disposeChunks(chunks) {", + " for (const chunk of chunks) {", + " for (const mesh of chunk.meshes) {", + " mesh.removeFromParent();", + " // Geometries and materials are the ones of the model.", + " mesh.dispose();", + " }", + " }", + " if (chunks === this.chunks) this.chunks = [];", + " }", + "", + " /** Place the copies again, for example after the ground or the object changed. */", + " rebuild() {", + " this._disposeChunks(this.chunks);", + " this.version++;", + " const { object } = this;", + " const spacing = this._getSpacing();", + " if (spacing <= 0 || this.model.parts.length === 0) {", + " this.grid = null;", + " return;", + " }", + " const cellsPerChunk = Math.max(Math.round(this._getChunkSize() / spacing), 1);", + " const grid = {", + " spacing,", + " cellsPerChunk,", + " cellsX: Math.ceil(object.getWidth() / spacing),", + " cellsY: Math.ceil(object.getHeight() / spacing),", + " };", + " this.grid = grid;", + " for (let firstCellJ = 0; firstCellJ < grid.cellsY; firstCellJ += cellsPerChunk) {", + " for (let firstCellI = 0; firstCellI < grid.cellsX; firstCellI += cellsPerChunk) {", + " this._createChunk(firstCellI, firstCellJ);", + " }", + " }", + " }", + "", + " /**", + " * Place again the copies of the chunks touching a rectangle of the scene,", + " * for example after painting.", + " */", + " _rebuildArea(minX, minY, maxX, maxY) {", + " const { grid, object } = this;", + " if (!grid) return;", + " const chunkSize = grid.spacing * grid.cellsPerChunk;", + " const firstChunkI = Math.max(Math.floor((minX - object.getX()) / chunkSize), 0);", + " const firstChunkJ = Math.max(Math.floor((minY - object.getY()) / chunkSize), 0);", + " const lastChunkI = Math.min(Math.floor((maxX - object.getX()) / chunkSize), Math.ceil(grid.cellsX / grid.cellsPerChunk) - 1);", + " const lastChunkJ = Math.min(Math.floor((maxY - object.getY()) / chunkSize), Math.ceil(grid.cellsY / grid.cellsPerChunk) - 1);", + " if (firstChunkI > lastChunkI || firstChunkJ > lastChunkJ) return;", + " const isInArea = (chunk) => {", + " const chunkI = chunk.firstCellI / grid.cellsPerChunk;", + " const chunkJ = chunk.firstCellJ / grid.cellsPerChunk;", + " return chunkI >= firstChunkI && chunkI <= lastChunkI && chunkJ >= firstChunkJ && chunkJ <= lastChunkJ;", + " };", + " this._disposeChunks(this.chunks.filter(isInArea));", + " this.chunks = this.chunks.filter((chunk) => !isInArea(chunk));", + " for (let chunkJ = firstChunkJ; chunkJ <= lastChunkJ; chunkJ++) {", + " for (let chunkI = firstChunkI; chunkI <= lastChunkI; chunkI++) {", + " this._createChunk(chunkI * grid.cellsPerChunk, chunkJ * grid.cellsPerChunk);", + " }", + " }", + " this.version++;", + " }", + "", + " _createChunk(firstCellI, firstCellJ) {", + " const { grid } = this;", + " const grounds = Array.from(this.placement.grounds);", + " /** @type {Copy[]} */", + " const copies = [];", + " for (let cellJ = firstCellJ; cellJ < Math.min(firstCellJ + grid.cellsPerChunk, grid.cellsY); cellJ++) {", + " for (let cellI = firstCellI; cellI < Math.min(firstCellI + grid.cellsPerChunk, grid.cellsX); cellI++) {", + " const copy = this._placeCopy(cellI, cellJ, grid.spacing, grounds);", + " if (copy) copies.push(copy);", + " }", + " }", + " if (copies.length === 0) return;", + "", + " const { object } = this;", + " // Copies are placed in scene units, and the object group is scaled", + " // from its inner area: they are scaled back to keep their proportions.", + " const scaleX = Math.max(object.getWidth() / AREA_SIZE, 0.0001);", + " const scaleY = Math.max(object.getHeight() / AREA_SIZE, 0.0001);", + " const scaleZ = Math.max(object.getDepth() / AREA_DEPTH, 0.0001);", + " const matrices = new Float32Array(copies.length * 16);", + " const tintColor = gdjs.rgbOrHexStringToNumber(object._getRandomTint());", + " const hasTint = tintColor !== 0xffffff;", + " const colors = hasTint ? new Float32Array(copies.length * 3) : null;", + " this._tint.setHex(tintColor);", + " const min = new THREE.Vector3(Infinity, Infinity, Infinity);", + " const max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);", + " copies.forEach((copy, index) => {", + " const cos = Math.cos(copy.angle) * copy.height;", + " const sin = Math.sin(copy.angle) * copy.height;", + " const localX = (copy.x - object.getX()) / scaleX;", + " const localY = (copy.y - object.getY()) / scaleY;", + " const localZ = (copy.z - object.getZ()) / scaleZ;", + " this._matrix.set(", + " cos / scaleX, -sin / scaleX, 0, localX,", + " sin / scaleY, cos / scaleY, 0, localY,", + " 0, 0, copy.height / scaleZ, localZ,", + " 0, 0, 0, 1", + " );", + " this._matrix.toArray(matrices, index * 16);", + " if (colors) {", + " // The tint of each copy is between white and the tint color.", + " this._color.setRGB(1, 1, 1).lerp(this._tint, createRandom(copy.key + 1)());", + " this._color.toArray(colors, index * 3);", + " }", + " const reach = (copy.height * Math.max(this.model.width, this.model.depth)) / 2;", + " min.min(this._chunkPosition.set(copy.x - reach, copy.y - reach, copy.z));", + " max.max(this._chunkPosition.set(copy.x + reach, copy.y + reach, copy.z + copy.height));", + " });", + " const instanceMatrix = new THREE.InstancedBufferAttribute(matrices, 16);", + " const instanceColor = colors ? new THREE.InstancedBufferAttribute(colors, 3) : null;", + " const castShadow = object._getCastShadow();", + " const receiveShadow = object._getReceiveShadow();", + " const meshes = this.model.parts.map((part) => {", + " const mesh = new THREE.InstancedMesh(part.geometry, part.material, 0);", + " // All the parts of the model share the positions of the copies.", + " mesh.instanceMatrix = instanceMatrix;", + " mesh.instanceColor = instanceColor;", + " mesh.count = copies.length;", + " mesh.computeBoundingSphere();", + " mesh.castShadow = castShadow;", + " mesh.receiveShadow = receiveShadow;", + " // The first mesh tests all the parts of the copies.", + " mesh.raycast = () => {};", + " this.group.add(mesh);", + " return mesh;", + " });", + " const center = new THREE.Vector3(", + " ((min.x + max.x) / 2 - object.getX()) / scaleX,", + " ((min.y + max.y) / 2 - object.getY()) / scaleY,", + " ((min.z + max.z) / 2 - object.getZ()) / scaleZ", + " );", + " const chunk = { firstCellI, firstCellJ, meshes, copies, center, radius: min.distanceTo(max) / 2 };", + " // Used by the scene editor to select the object when a copy is clicked.", + " meshes[0].raycast = (raycaster, intersects) => this._raycastChunk(chunk, raycaster, intersects);", + " this.chunks.push(chunk);", + " }", + "", + " /**", + " * Add the hits of a ray on the copies of a chunk, like they are drawn. There", + " * can be thousands of copies: only the ones whose box is crossed by the ray", + " * are tested with the triangles of the model.", + " * @param {{meshes: THREE.InstancedMesh[], copies: Copy[], center: THREE.Vector3, radius: number}} chunk", + " * @param {THREE.Raycaster} raycaster", + " * @param {THREE.Intersection[]} intersects", + " */", + " _raycastChunk(chunk, raycaster, intersects) {", + " const { object, group } = this;", + " this._raycastSphere.center.copy(chunk.center).applyMatrix4(group.matrixWorld);", + " this._raycastSphere.radius = chunk.radius / getWorldScale(object);", + " if (!raycaster.ray.intersectsSphere(this._raycastSphere)) return;", + "", + " // The ray in the scene coordinates, like the copies.", + " const scale = this._raycastScale.set(", + " Math.max(object.getWidth() / AREA_SIZE, 0.0001),", + " Math.max(object.getHeight() / AREA_SIZE, 0.0001),", + " Math.max(object.getDepth() / AREA_DEPTH, 0.0001)", + " );", + " const ray = this._raycastRay.copy(raycaster.ray).applyMatrix4(this._raycastInverseMatrix.copy(group.matrixWorld).invert());", + " ray.origin.multiply(scale).add(this._chunkPosition.set(object.getX(), object.getY(), object.getZ()));", + " ray.direction.multiply(scale);", + "", + " const reachPerHeight = Math.max(this.model.width, this.model.depth) / 2;", + " const instanceMatrices = chunk.meshes[0].instanceMatrix.array;", + " chunk.copies.forEach((copy, index) => {", + " const reach = copy.height * reachPerHeight;", + " this._raycastBox.min.set(copy.x - reach, copy.y - reach, copy.z);", + " this._raycastBox.max.set(copy.x + reach, copy.y + reach, copy.z + copy.height);", + " if (!ray.intersectsBox(this._raycastBox)) return;", + " this._raycastMesh.matrixWorld.fromArray(instanceMatrices, index * 16).premultiply(group.matrixWorld);", + " for (const mesh of chunk.meshes) {", + " this._raycastMesh.geometry = mesh.geometry;", + " this._raycastMesh.material = mesh.material;", + " this._raycastHits.length = 0;", + " this._raycastMesh.raycast(raycaster, this._raycastHits);", + " for (const hit of this._raycastHits) {", + " hit.object = mesh;", + " hit.instanceId = index;", + " intersects.push(hit);", + " }", + " }", + " });", + " }", + "", + " /** @param {THREE.Camera | null} camera */", + " _hideFarChunks(camera) {", + " if (!camera) return;", + " const worldScale = getWorldScale(this.object);", + " const drawDistance = Math.max(this.object._getDrawDistance(), 1) / worldScale;", + " this.uniforms.scatterDrawDistance.value = drawDistance;", + " this._cameraPosition.setFromMatrixPosition(camera.matrixWorld);", + " for (const chunk of this.chunks) {", + " const distance = this._chunkPosition", + " .copy(chunk.center)", + " .applyMatrix4(this.group.matrixWorld)", + " .distanceTo(this._cameraPosition);", + " const isVisible = distance - chunk.radius / worldScale < drawDistance;", + " for (const mesh of chunk.meshes) mesh.visible = isVisible;", + " }", + " }", + "", + " /**", + " * @param {number} elapsedSeconds", + " * @param {THREE.Camera | null} camera", + " */", + " update(elapsedSeconds, camera) {", + " if (this.placement.shouldPlaceAgain(elapsedSeconds, this._getPlacementKey())) {", + " this.rebuild();", + " }", + " if (!this.changedSamples.isEmpty()) {", + " const { object } = this;", + " const sampleWidth = object.getWidth() / MASK_RESOLUTION;", + " const sampleHeight = object.getHeight() / MASK_RESOLUTION;", + " const { minI, minJ, maxI, maxJ } = this.changedSamples;", + " // Copies between samples use the density of the samples around them.", + " this._rebuildArea(", + " object.getX() + (minI - 1) * sampleWidth,", + " object.getY() + (minJ - 1) * sampleHeight,", + " object.getX() + (maxI + 1) * sampleWidth,", + " object.getY() + (maxJ + 1) * sampleHeight", + " );", + " this.changedSamples.clear();", + " }", + " // The object transformation is applied just before rendering, it's needed now.", + " this.object.getRenderer().ensureUpToDate();", + " this.group.updateWorldMatrix(true, false);", + " this._hideFarChunks(camera);", + " this._updateSurface();", + " }", + "", + " _updateSurface() {", + " const { object } = this;", + " if (typeof object.setSurface !== 'function') return;", + " const trunkKey = object._getTrunkCollisions() + '|' + object._getTrunkDiameter();", + " if (trunkKey !== this.trunkKey) {", + " this.trunkKey = trunkKey;", + " this.version++;", + " }", + " if (object.getSurface() !== this.surface) object.setSurface(this.surface);", + " }", + "", + " /** @returns {Copy[]} */", + " getCopies() {", + " const copies = [];", + " for (const chunk of this.chunks) copies.push(...chunk.copies);", + " return copies;", + " }", + "", + " /**", + " * @returns {Copy | null} The copy whose base is the nearest to a position (on X and Y), if any.", + " */", + " findNearestCopy(x, y) {", + " let nearestCopy = null;", + " let nearestDistanceSquared = Infinity;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " const distanceSquared = (copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y);", + " if (distanceSquared < nearestDistanceSquared) {", + " nearestDistanceSquared = distanceSquared;", + " nearestCopy = copy;", + " }", + " }", + " }", + " return nearestCopy;", + " }", + "", + " getCopyCount() {", + " let count = 0;", + " for (const chunk of this.chunks) count += chunk.copies.length;", + " return count;", + " }", + "", + " /** Remove the copies whose base is in a circle (they come back when the scene is restarted). */", + " removeCopies(x, y, radius) {", + " let hasRemovedCopies = false;", + " for (const chunk of this.chunks) {", + " for (const copy of chunk.copies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.set(copy.key, copy);", + " hasRemovedCopies = true;", + " }", + " }", + " }", + " if (hasRemovedCopies) this._rebuildArea(x - radius, y - radius, x + radius, y + radius);", + " }", + "", + " /** Paint the full density around a position, and bring back the copies removed there. */", + " addCopies(x, y, radius) {", + " for (const [key, copy] of this.removedCopies) {", + " if ((copy.x - x) * (copy.x - x) + (copy.y - y) * (copy.y - y) <= radius * radius) {", + " this.removedCopies.delete(key);", + " }", + " }", + " this.paint(x, y, x, y, radius, 1, 1);", + " }", + "", + " _getStroke(x1, y1, x2, y2, radius) {", + " const { object } = this;", + " const stroke = this._stroke;", + " stroke.cellWidth = object.getWidth() / MASK_RESOLUTION;", + " stroke.cellHeight = object.getHeight() / MASK_RESOLUTION;", + " stroke.ax = x1 - object.getX();", + " stroke.ay = y1 - object.getY();", + " stroke.bx = x2 - object.getX();", + " stroke.by = y2 - object.getY();", + " stroke.radius = Math.max(radius, 0);", + " return stroke;", + " }", + "", + " /**", + " * Paint the density around a segment (copies are placed again at the next frame).", + " * @param {number} density From 0 (erase) to 1 (as dense as the Density property).", + " * @param {number} strength From 0 to 1.", + " */", + " paint(x1, y1, x2, y2, radius, density, strength) {", + " const changedSamples = new SampleRectangle();", + " this.mask.paint(this._getStroke(x1, y1, x2, y2, radius), density, strength, changedSamples);", + " this.changedSamples.add(changedSamples);", + " }", + "", + " /** @param {DensityMask} mask */", + " setMask(mask) {", + " this.mask = mask;", + " this.rebuild();", + " }", + "", + " /**", + " * Prisms around the trunks, from 0 to 1 in the object box (see `gdjs.Surface`).", + " * @returns {gdjs.SurfaceTriangles}", + " */", + " _getTrunkTriangles() {", + " const { object } = this;", + " const copies = object._getTrunkCollisions() ? this.getCopies() : [];", + " const verticesPerCopy = TRUNK_SIDES * 2 + 1;", + " const positions = new Float32Array(copies.length * verticesPerCopy * 3);", + " const indices = new Uint32Array(copies.length * TRUNK_SIDES * 3 * 3);", + " const width = object.getWidth() || 1;", + " const height = object.getHeight() || 1;", + " const depth = object.getDepth() || 1;", + " let indexOffset = 0;", + " copies.forEach((copy, copyIndex) => {", + " const radius = (Math.max(object._getTrunkDiameter(), 0) / 2) * (copy.height / Math.max(object._getSize(), 1));", + " const top = copy.z + copy.height * 0.8;", + " const firstVertex = copyIndex * verticesPerCopy;", + " const setVertex = (vertex, x, y, z) => {", + " positions[vertex * 3] = (x - object.getX()) / width;", + " positions[vertex * 3 + 1] = (y - object.getY()) / height;", + " positions[vertex * 3 + 2] = (z - object.getZ()) / depth;", + " };", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const angle = ((side + 0.5) / TRUNK_SIDES) * Math.PI * 2;", + " const x = copy.x + Math.cos(angle) * radius;", + " const y = copy.y + Math.sin(angle) * radius;", + " // Starting a bit under the ground, which can be sloped.", + " setVertex(firstVertex + side * 2, x, y, copy.z - radius);", + " setVertex(firstVertex + side * 2 + 1, x, y, top);", + " }", + " const center = firstVertex + TRUNK_SIDES * 2;", + " setVertex(center, copy.x, copy.y, top);", + " for (let side = 0; side < TRUNK_SIDES; side++) {", + " const bottom = firstVertex + side * 2;", + " const nextBottom = firstVertex + ((side + 1) % TRUNK_SIDES) * 2;", + " // Triangles face out of the prism (vertices at odd indices are at the top).", + " indices.set([bottom, nextBottom, bottom + 1, nextBottom, nextBottom + 1, bottom + 1], indexOffset);", + " indices.set([center, bottom + 1, nextBottom + 1], indexOffset + 6);", + " indexOffset += 9;", + " }", + " });", + " if (copies.length === 0) {", + " // Without triangles, the physics engine and navigation meshes would use", + " // the object box: a tiny triangle under the object is used instead.", + " return { positions: new Float32Array([0, 0, -1, 0.0001, 0, -1, 0, 0.0001, -1]), indices: new Uint32Array([0, 2, 1]) };", + " }", + " return { positions, indices };", + " }", + "", + " dispose() {", + " this.isDisposed = true;", + " if (typeof this.object.setSurface === 'function' && this.object.getSurface() === this.surface) {", + " this.object.setSurface(null);", + " }", + " this._disposeChunks(this.chunks);", + " this._disposeModel();", + " this.group.removeFromParent();", + " }", + "}", + "", + "const scatterToolIcons = {", + " Add: svgIcon(", + " ''", + " ),", + " Erase: svgIcon(", + " ''", + " ),", + "};", + "", + "/**", + " * The brushes shown in the scene editor when scattered models are selected,", + " * to add or erase copies. Without the needed editor functions (older GDevelop", + " * versions), nothing is shown: copies can still be painted with events.", + " */", + "class ScatterEditorTools {", + " constructor() {", + " /** '' when no brush is used. */", + " this.toolName = '';", + " this.sizePercent = 30;", + " this.strengthPercent = 50;", + " /** @type {Scatter | null} */", + " this.scatter = null;", + " /** @type {gdjs.InGameEditor | null} */", + " this.editor = null;", + " this.isStroking = false;", + " this.lastStrokeTime = 0;", + " /** @type {Array<{mask: DensityMask, baseMask: DensityMask}>} */", + " this.undoSteps = [];", + " this.raycaster = new THREE.Raycaster();", + " this.ndc = new THREE.Vector2();", + " this._groundAtCursor = { ground: null, z: 0 };", + " /** A circle following the ground under the cursor. */", + " this.brushRing = new THREE.LineLoop(", + " new THREE.BufferGeometry().setAttribute('position', new THREE.BufferAttribute(new Float32Array(64 * 3), 3)),", + " new THREE.LineBasicMaterial({ color: 0xffffff, depthTest: false, transparent: true })", + " );", + " this.brushRing.renderOrder = 1000;", + " this.brushRing.frustumCulled = false;", + " this.brushRing.raycast = () => {};", + " }", + "", + " /** @param {gdjs.InGameEditor} editor */", + " update(editor) {", + " if (typeof editor.showToolbar !== 'function') return;", + " this.editor = editor;", + " const selectedObjects = editor.getSelectedObjects();", + " const scatter =", + " selectedObjects.length === 1 && selectedObjects[0].__terrainScatter ? selectedObjects[0].__terrainScatter : null;", + " if (scatter !== this.scatter) {", + " this._endStroke();", + " this.scatter = scatter;", + " this.undoSteps.length = 0;", + " }", + " if (scatter) editor.showToolbar('ScatteredModels', this._getToolbarItems());", + " const game = editor.getRuntimeGame();", + " if (!scatter || !this.toolName) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const inputManager = game.getInputManager();", + " if (inputManager.wasKeyJustPressed(gdjs.evtTools.input.keysNameToCode.Escape)) {", + " this._endStroke();", + " this.toolName = '';", + " this.brushRing.removeFromParent();", + " return;", + " }", + " editor.captureLeftMouseButton();", + " const hit = this._getPositionUnderCursor(scatter, game);", + " const radius = this._getRadius();", + " this._showBrushRing(scatter, hit, radius);", + "", + " const isPressedForTool =", + " typeof editor.isCapturedLeftMouseButtonPressed === 'function'", + " ? editor.isCapturedLeftMouseButtonPressed()", + " : inputManager.isMouseButtonPressed(0);", + " // The button is released outside the canvas when the mouse is on a toolbar.", + " const isPressed = isPressedForTool && inputManager.isMouseInsideCanvas();", + " if (isPressed && hit && !this.isStroking) {", + " this._startStroke(scatter);", + " }", + " if (this.isStroking && isPressed && hit) {", + " this._applyBrush(scatter, hit, radius);", + " }", + " if (!isPressed) {", + " this._endStroke();", + " }", + " }", + "", + " _getRadius() {", + " const { object } = this.scatter;", + " const maxRadius = Math.max(object.getWidth(), object.getHeight()) / 4;", + " return Math.max(maxRadius * Math.pow(this.sizePercent / 100, 2), 10);", + " }", + "", + " /**", + " * @returns {{x: number, y: number} | null} The position of the scene under the cursor: on the", + " * highest ground hit, or on the plane at the object Z.", + " */", + " _getPositionUnderCursor(scatter, game) {", + " let hit = null;", + " for (const ground of getGrounds(scatter.object.getRuntimeScene())) {", + " if (typeof ground.raycastFromCursor !== 'function') continue;", + " const localHit = ground.raycastFromCursor(game, this.raycaster, this.ndc);", + " if (!localHit) continue;", + " const sceneHit = ground.toScenePosition(localHit);", + " if (!hit || sceneHit.z > hit.z) hit = sceneHit;", + " }", + " if (hit) return hit;", + "", + " const { object } = scatter;", + " const layer = object.getInstanceContainer().getLayer(object.getLayer());", + " const camera = layer.getRenderer().getThreeCamera();", + " if (!camera) return null;", + " const inputManager = game.getInputManager();", + " this.ndc.set(", + " (inputManager.getCursorX() / game.getGameResolutionWidth()) * 2 - 1,", + " -(inputManager.getCursorY() / game.getGameResolutionHeight()) * 2 + 1", + " );", + " this.raycaster.setFromCamera(this.ndc, camera);", + " scatter.group.updateWorldMatrix(true, false);", + " const ray = this.raycaster.ray.clone().applyMatrix4(scatter.group.matrixWorld.clone().invert());", + " const point = ray.intersectPlane(new THREE.Plane(new THREE.Vector3(0, 0, 1), 0), new THREE.Vector3());", + " if (!point) return null;", + " return {", + " x: object.getX() + (point.x / AREA_SIZE) * object.getWidth(),", + " y: object.getY() + (point.y / AREA_SIZE) * object.getHeight(),", + " };", + " }", + "", + " _showBrushRing(scatter, hit, radius) {", + " if (!hit) {", + " this.brushRing.removeFromParent();", + " return;", + " }", + " const { object } = scatter;", + " if (this.brushRing.parent !== scatter.group) scatter.group.add(this.brushRing);", + " const grounds = getGrounds(object.getRuntimeScene());", + " const positions = this.brushRing.geometry.attributes.position;", + " for (let index = 0; index < positions.count; index++) {", + " const angle = (index / positions.count) * Math.PI * 2;", + " const x = hit.x + Math.cos(angle) * radius;", + " const y = hit.y + Math.sin(angle) * radius;", + " const { ground, z } = findHighestGround(grounds, x, y, this._groundAtCursor);", + " positions.setXYZ(", + " index,", + " ((x - object.getX()) / object.getWidth()) * AREA_SIZE,", + " ((y - object.getY()) / object.getHeight()) * AREA_SIZE,", + " (((ground ? z : object.getZ()) + 2 - object.getZ()) / Math.max(object.getDepth(), 0.0001)) * AREA_DEPTH", + " );", + " }", + " positions.needsUpdate = true;", + " }", + "", + " _startStroke(scatter) {", + " this.isStroking = true;", + " this.lastStrokeTime = performance.now();", + " this.undoSteps.push({ mask: scatter.mask.clone(), baseMask: scatter.baseMask });", + " while (this.undoSteps.length > 30) this.undoSteps.shift();", + " }", + "", + " _endStroke() {", + " if (!this.isStroking) return;", + " this.isStroking = false;", + " this._save();", + " }", + "", + " _applyBrush(scatter, hit, radius) {", + " const now = performance.now();", + " const elapsedSeconds = Math.min((now - this.lastStrokeTime) / 1000, 0.1);", + " this.lastStrokeTime = now;", + " const strength = (this.strengthPercent / 100) * elapsedSeconds * 8;", + " scatter.paint(hit.x, hit.y, hit.x, hit.y, radius, this.toolName === 'Add' ? 1 : 0, strength);", + " }", + "", + " _save() {", + " const { scatter, editor } = this;", + " if (!scatter || !editor) return;", + " editor.updateObjectProperties(scatter.object.getName(), { PaintData: scatter.save() });", + " }", + "", + " _undo() {", + " const undoStep = this.undoSteps.pop();", + " // The coverage or the edits may have changed since the stroke.", + " if (!this.scatter || !undoStep || undoStep.baseMask !== this.scatter.baseMask) {", + " this.undoSteps.length = 0;", + " return;", + " }", + " this.scatter.setMask(undoStep.mask);", + " this._save();", + " }", + "", + " /** @returns {Array} */", + " _getToolbarItems() {", + " const toolButton = (toolName, tooltip) => ({", + " type: 'button',", + " id: toolName,", + " tooltip,", + " iconUrl: scatterToolIcons[toolName],", + " isActive: this.toolName === toolName,", + " onClick: () => (this.toolName = this.toolName === toolName ? '' : toolName),", + " });", + " return [", + " toolButton('Add', 'Add copies (drag on the ground)'),", + " toolButton('Erase', 'Erase copies'),", + " { type: 'divider', id: 'BrushDivider' },", + " {", + " type: 'slider',", + " id: 'Size',", + " tooltip: 'Brush size',", + " iconUrl: toolIcons.Size,", + " min: 1,", + " max: 100,", + " value: this.sizePercent,", + " onChange: (value) => (this.sizePercent = value),", + " },", + " {", + " type: 'slider',", + " id: 'Strength',", + " tooltip: 'Brush strength',", + " iconUrl: toolIcons.Strength,", + " min: 5,", + " max: 100,", + " value: this.strengthPercent,", + " onChange: (value) => (this.strengthPercent = value),", + " },", + " {", + " type: 'button',", + " id: 'Undo',", + " tooltip: 'Undo the last stroke on these scattered models',", + " iconUrl: toolIcons.Undo,", + " onClick: () => this._undo(),", + " },", + " ];", + " }", + "}", + "", + "const editorTools = new ScatterEditorTools();", + "if (gdjs.registerInGameEditorPostStepCallback) {", + " gdjs.registerInGameEditorPostStepCallback((editor) => editorTools.update(editor));", + "}", + "", + "gdjs.__terrainScatterExtension = {", + " Scatter,", + " // Exposed for tests.", + " DensityMask,", + " maskCodec,", + " applyEdits,", + "};", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "DefineHelperClasses" + }, + { + "functionName": "DefineGrassHelperClasses" + }, + { + "functionName": "DefineScatterHelperClasses" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [ + { + "areaMaxX": 4096, + "areaMaxY": 4096, + "areaMaxZ": 600, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d terrains", + "defaultName": "Terrain", + "description": "A ground with hills, mountains or valleys that can be sculpted and painted in the scene editor, or changed with events. Add the 3D physics behavior to it to make objects walk or roll on it.", + "fullName": "3D terrain", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLXRlcnJhaW4iIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBkPSJNMTQsNkwxMC4yNSwxMUwxMy4xLDE0LjhMMTEuNSwxNkM5LjgxLDEzLjc1IDcsMTAgNywxMEwxLDE4SDIzTDE0LDZaIiAvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "Terrain3D", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 4096, + "height": 4096, + "depth": 600, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 600, + "height": 4096, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-004096004096", + "width": 4096, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrain3D) object.__terrain3D.dispose();", + "object.__terrain3D = new gdjs.__terrain3DExtension.Terrain(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.update();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground around a position (or lower it with a negative height). It's raised the most at the center and less and less up to the radius.", + "fullName": "Raise or lower the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGround", + "sentence": "Raise the ground of _PARAM0_ by _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x, y, x, y, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Raise the ground along a line, for example for a ridge, or lower it with a negative height to dig a river bed or a valley.", + "fullName": "Raise or lower the ground along a line", + "functionType": "Action", + "group": "Sculpt", + "name": "RaiseGroundAlongLine", + "sentence": "Raise the ground of _PARAM0_ by _PARAM6_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const height = eventsFunctionContext.getArgument(\"Height\");", + "object.__terrain3D.raise(x1, y1, x2, y2, radius, height);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Height to add (negative to lower the ground)", + "name": "Height", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Flatten the ground around a position to a given height, for example to place a building.", + "fullName": "Flatten the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "FlattenGround", + "sentence": "Flatten the ground of _PARAM0_ to a Z of _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const z = eventsFunctionContext.getArgument(\"Z\");", + "object.__terrain3D.flatten(x, y, x, y, radius, z, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Z position of the flat ground", + "name": "Z", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Smooth the ground around a position, softening bumps and cliffs.", + "fullName": "Smooth the ground", + "functionType": "Action", + "group": "Sculpt", + "name": "SmoothGround", + "sentence": "Smooth the ground of _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_ (strength: _PARAM4_)", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const strength = eventsFunctionContext.getArgument(\"Strength\");", + "object.__terrain3D.smooth(x, y, x, y, radius, strength);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Strength (between 0 and 1)", + "name": "Strength", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer (like grass, dirt, rock or sand) on the ground around a position.", + "fullName": "Paint a layer", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayer", + "sentence": "Paint layer _PARAM4_ on _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x, y, x, y, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Paint a layer on the ground along a line, for example for a path or a road.", + "fullName": "Paint a layer along a line", + "functionType": "Action", + "group": "Paint", + "name": "PaintLayerAlongLine", + "sentence": "Paint layer _PARAM6_ on _PARAM0_ from _PARAM1_; _PARAM2_ to _PARAM3_; _PARAM4_ with a radius of _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x1 = eventsFunctionContext.getArgument(\"X1\");", + "const y1 = eventsFunctionContext.getArgument(\"Y1\");", + "const x2 = eventsFunctionContext.getArgument(\"X2\");", + "const y2 = eventsFunctionContext.getArgument(\"Y2\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const layer = eventsFunctionContext.getArgument(\"Layer\");", + "object.__terrain3D.paint(x1, y1, x2, y2, radius, layer, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the start", + "name": "X1", + "type": "expression" + }, + { + "description": "Y position of the start", + "name": "Y1", + "type": "expression" + }, + { + "description": "X position of the end", + "name": "X2", + "type": "expression" + }, + { + "description": "Y position of the end", + "name": "Y2", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance from the line.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Layer (1 to 4)", + "name": "Layer", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Tint the ground around a position with a color multiplying its layers, like dry grass or darker mud. White removes the tint.", + "fullName": "Tint the ground", + "functionType": "Action", + "group": "Paint", + "name": "TintGround", + "sentence": "Tint the ground of _PARAM0_ with _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const color = gdjs.rgbOrHexToRGBColor(eventsFunctionContext.getArgument(\"Color\"));", + "object.__terrain3D.tint(x, y, x, y, radius, color, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Color", + "name": "Color", + "type": "color" + } + ], + "objectGroups": [] + }, + { + "description": "Make the ground around a position wet (darker and shiny, like after rain or near water) or dry.", + "fullName": "Change the wetness of the ground", + "functionType": "Action", + "group": "Paint", + "name": "WetGround", + "sentence": "Change the wetness of the ground of _PARAM0_ to _PARAM4_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const wetness = eventsFunctionContext.getArgument(\"Wetness\");", + "object.__terrain3D.wet(x, y, x, y, radius, wetness, 1);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "longDescription": "The effect fades out smoothly up to this distance.", + "name": "Radius", + "type": "expression" + }, + { + "description": "Wetness (from 0 for dry to 1)", + "name": "Wetness", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the wetness of the ground at a position, from 0 (dry) to 1, painted or near the water (wet shore).", + "fullName": "Ground wetness", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundWetness", + "sentence": "the wetness of the ground at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getWetnessAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The tint painted on the ground at a position, like \"255;255;255\" (white when there is none).", + "fullName": "Ground tint", + "functionType": "StringExpression", + "group": "Paint", + "name": "GroundTint", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getTintAt(x, y).join(\";\");" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "string" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the ground in a circle, for the entrance of a tunnel, a cave or a well: there is nothing drawn and no collision there. Fill it again with the \"Fill holes\" action. A height field can't go under itself: put a 3D model (with a collision shape) for the tunnel or the cave under the ground. The physics engine removes the triangles touching a hole, so the hole in the collisions can be up to a cell larger than the one drawn: make the model go a bit further than the hole, or put rocks around the entrance.", + "fullName": "Make a hole", + "functionType": "Action", + "group": "Holes", + "name": "MakeHole", + "sentence": "Make a hole in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.makeHole(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Fill the holes in a circle with the layers of the ground around them: the ground is drawn and has collisions again.", + "fullName": "Fill holes", + "functionType": "Action", + "group": "Holes", + "name": "FillHoles", + "sentence": "Fill the holes in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrain3D.fillHoles(x, y, x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Make the entrance of a tunnel or a cave on a slope: a hole, with the ground in front of it flattened to the floor of the tunnel.", + "fullName": "Carve an entrance", + "functionType": "Action", + "group": "Holes", + "name": "CarveEntrance", + "sentence": "Carve an entrance in _PARAM0_ at _PARAM1_; _PARAM2_ with a radius of _PARAM3_, going in at _PARAM4_° with its floor at Z _PARAM5_ and _PARAM6_ pixels of flat ground in front", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "const angle = eventsFunctionContext.getArgument(\"Angle\");", + "const floorZ = eventsFunctionContext.getArgument(\"FloorZ\");", + "const length = eventsFunctionContext.getArgument(\"Length\");", + "object.__terrain3D.carveEntrance(x, y, radius, angle, floorZ, length);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + }, + { + "description": "Direction going into the ground (in degrees)", + "name": "Angle", + "type": "expression" + }, + { + "description": "Z position of the floor", + "name": "FloorZ", + "type": "expression" + }, + { + "description": "Length of the flat ground in front of the entrance (in pixels)", + "name": "Length", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Check if there is a hole in the ground at a position.", + "fullName": "Hole", + "functionType": "Condition", + "group": "Holes", + "name": "IsHole", + "sentence": "There is a hole in _PARAM0_ at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.isHoleAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the ground at a position, or the given value where there is a hole.", + "fullName": "Ground Z position, with holes", + "functionType": "Expression", + "group": "Holes", + "name": "GroundZWithHoles", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const terrain = object.__terrain3D;", + "eventsFunctionContext.returnValue = terrain.isHoleAt(x, y) ? eventsFunctionContext.getArgument(\"ZInHoles\") : terrain.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + }, + { + "description": "Value in holes", + "longDescription": "For example, a Z position far under the ground.", + "name": "ZInHoles", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with a generated relief. Painted layers are reset.", + "fullName": "Generate a relief", + "functionType": "Action", + "group": "Generation", + "name": "GenerateRelief", + "sentence": "Generate a relief of _PARAM1_ on _PARAM0_ with seed _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const relief = eventsFunctionContext.getArgument(\"Relief\");", + "const seed = eventsFunctionContext.getArgument(\"Seed\");", + "object.__terrain3D.generate(relief, seed);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Relief", + "name": "Relief", + "supplementaryInformation": "[\"Flat\", \"Hills\", \"Mountains\", \"Island\"]", + "type": "stringWithSelector" + }, + { + "description": "Seed", + "longDescription": "Each seed gives a different terrain with the same relief.", + "name": "Seed", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Replace the ground with the heights of an image. Painted layers are kept.", + "fullName": "Load a heightmap", + "functionType": "Action", + "group": "Generation", + "name": "LoadHeightmap", + "sentence": "Load the heights of _PARAM0_ from _PARAM1_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const image = eventsFunctionContext.getArgument(\"Image\");", + "object.__terrain3D.loadHeightmap(image);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Heightmap image", + "longDescription": "Black is the lowest, white the highest. For more precision, store the height on 16 bits in the red (most significant byte) and green channels.", + "name": "Image", + "type": "imageResource" + } + ], + "objectGroups": [] + }, + { + "description": "Move objects up or down so that their bottom is on the ground, under their center. Useful to place trees, rocks or characters on a terrain.", + "fullName": "Put objects on the ground", + "functionType": "Action", + "group": "Position", + "name": "PutOnGround", + "sentence": "Put _PARAM1_ on the ground of _PARAM0_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrain3D.placeOnGround(eventsFunctionContext.getObjects(\"Objects\"));" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "Objects to put on the ground", + "name": "Objects", + "type": "objectList" + } + ], + "objectGroups": [] + }, + { + "description": "the Z position of the ground at a position of the scene.", + "fullName": "Ground Z position", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundZ", + "sentence": "the ground Z position at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getHeightAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the slope of the ground (angle with the horizontal, in degrees) at a position of the scene.", + "fullName": "Ground slope", + "functionType": "ExpressionAndCondition", + "group": "Position", + "name": "GroundSlope", + "sentence": "the ground slope at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getSlopeAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the layer (from 1 to 4) painted the most at a position of the scene. Useful to play footstep sounds or to slow down characters in water or mud.", + "fullName": "Ground layer", + "functionType": "ExpressionAndCondition", + "group": "Paint", + "name": "GroundLayer", + "sentence": "the ground layer at _PARAM1_; _PARAM2_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "eventsFunctionContext.returnValue = object.__terrain3D.getLayerAt(x, y);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::Terrain3D", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Sculpt", + "children": [ + { + "functionName": "RaiseGround" + }, + { + "functionName": "RaiseGroundAlongLine" + }, + { + "functionName": "FlattenGround" + }, + { + "functionName": "SmoothGround" + } + ] + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "PaintLayer" + }, + { + "functionName": "PaintLayerAlongLine" + }, + { + "functionName": "TintGround" + }, + { + "functionName": "WetGround" + }, + { + "functionName": "GroundWetness" + }, + { + "functionName": "GroundTint" + }, + { + "functionName": "GroundLayer" + } + ] + }, + { + "folderName": "Holes", + "children": [ + { + "functionName": "MakeHole" + }, + { + "functionName": "FillHoles" + }, + { + "functionName": "CarveEntrance" + }, + { + "functionName": "IsHole" + }, + { + "functionName": "GroundZWithHoles" + } + ] + }, + { + "folderName": "Generation", + "children": [ + { + "functionName": "GenerateRelief" + }, + { + "functionName": "LoadHeightmap" + } + ] + }, + { + "folderName": "Position", + "children": [ + { + "functionName": "PutOnGround" + }, + { + "functionName": "GroundZ" + }, + { + "functionName": "GroundSlope" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "Hills", + "type": "Choice", + "label": "Relief", + "description": "The initial shape, before sculpting.", + "group": "Shape", + "choices": [ + { + "label": "Flat", + "value": "Flat" + }, + { + "label": "Hills", + "value": "Hills" + }, + { + "label": "Mountains", + "value": "Mountains" + }, + { + "label": "Island", + "value": "Island" + } + ], + "name": "Relief" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed gives a different terrain with the same relief.", + "group": "Shape", + "name": "Seed" + }, + { + "value": "", + "type": "Resource", + "label": "Heightmap image", + "description": "Optional. Replaces the relief: black is the lowest, white the highest (the object depth).", + "group": "Shape", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "HeightmapImage" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Changes of the relief or heightmap, applied in order, as a JSON list, for example [{\"tool\": \"raise\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15, \"height\": 0.4}, {\"tool\": \"paint\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02, \"layer\": 2}]. Tools: raise (height added to the ground, negative to lower), flatten (z: the ground is brought to this height, fully at the center, cutting what is above it and filling what is below; with toX and toY, toZ gives the height at the end of the line, for a road going up), smooth (strength), paint (layer, from 1 to 4, and strength), tint (color, like \"120;140;60\", multiplying the layers, white removing the tint, and strength), wetness (amount, from 0 for dry to 1 for wet, and strength), hole (no ground in the radius, for the entrances of tunnels and caves) and fill (the holes in the radius are filled with the layers of the ground around them). x, y and radius are fractions (0 to 1) of the terrain size (x is (scene X - terrain X) / terrain width). height and z are fractions of its depth: the ground at z is at Z = terrain Z + z * terrain depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", + "group": "Shape", + "advanced": true, + "name": "Edits" + }, + { + "value": "256", + "type": "Choice", + "label": "Resolution", + "description": "The number of cells on each side of the terrain. Higher is more detailed but slower.", + "group": "Shape", + "choices": [ + { + "label": "64 x 64", + "value": "64" + }, + { + "label": "128 x 128", + "value": "128" + }, + { + "label": "256 x 256", + "value": "256" + }, + { + "label": "512 x 512", + "value": "512" + }, + { + "label": "1024 x 1024", + "value": "1024" + } + ], + "name": "Resolution" + }, + { + "value": "96;160;64", + "type": "Color", + "label": "Layer 1 color (grass)", + "group": "Layers", + "name": "Layer1Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 1 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer1NormalMap" + }, + { + "value": "150;112;72", + "type": "Color", + "label": "Layer 2 color (dirt)", + "group": "Layers", + "name": "Layer2Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 2 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer2NormalMap" + }, + { + "value": "124;118;112", + "type": "Color", + "label": "Layer 3 color (rock)", + "group": "Layers", + "name": "Layer3Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 3 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer3NormalMap" + }, + { + "value": "224;204;148", + "type": "Color", + "label": "Layer 4 color (sand)", + "group": "Layers", + "name": "Layer4Color" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 texture", + "description": "Optional. Tinted by the layer color.", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4Texture" + }, + { + "value": "", + "type": "Resource", + "label": "Layer 4 normal map", + "description": "Optional. The bumps of the texture, lit by the lights (an OpenGL normal map, like the textures of ambientCG).", + "group": "Layers", + "extraInformation": [ + "image" + ], + "choices": [], + "name": "Layer4NormalMap" + }, + { + "value": "1", + "type": "Number", + "label": "Normal map strength", + "description": "How much the normal maps bump the ground: 0 for none, 1 as they are, more to exaggerate them.", + "group": "Layers", + "name": "NormalMapStrength" + }, + { + "value": "256", + "type": "Number", + "unit": "Pixel", + "label": "Texture size", + "description": "The size, in the scene, of one repetition of the layer textures.", + "group": "Layers", + "name": "TextureSize" + }, + { + "value": "0.5", + "type": "Number", + "label": "Height blending", + "description": "Where layers meet, the bright parts of textures (stones, tufts) cover the dark ones (gaps, sand) instead of fading into each other: 0 for none, 1 for the most.", + "group": "Layers", + "name": "HeightBlending" + }, + { + "value": "0.5", + "type": "Number", + "label": "Texture variation", + "description": "Makes the repetition of textures less visible, with patches of bigger and rotated textures and colors slowly varying: 0 for none, 1 for the most.", + "group": "Layers", + "name": "TextureVariation" + }, + { + "value": "false", + "type": "Boolean", + "label": "Wet shore", + "description": "Make the ground wet (darker and shiny) under a Z position, like the sand of a beach near the water.", + "group": "Wetness", + "name": "WetShore" + }, + { + "value": "0", + "type": "Number", + "unit": "Pixel", + "label": "Wet below Z", + "description": "The ground is wet under this Z position (for example, the Z of a 3D water object).", + "group": "Wetness", + "name": "WetShoreZ" + }, + { + "value": "60", + "type": "Number", + "unit": "Pixel", + "label": "Wet shore fade", + "description": "The ground becomes dry over this height above \"Wet below Z\".", + "group": "Wetness", + "name": "WetShoreFade" + }, + { + "value": "3", + "type": "Choice", + "label": "Layer on steep slopes", + "description": "This layer is shown where the ground is steep, whatever is painted.", + "group": "Layers", + "choices": [ + { + "label": "None", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "CliffLayer" + }, + { + "value": "45", + "type": "Number", + "unit": "DegreeAngle", + "label": "Steep slope angle", + "group": "Layers", + "name": "CliffAngle" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "String", + "label": "Sculpted and painted data", + "description": "Written by the sculpt and paint tools of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the relief, heightmap and edits.", + "advanced": true, + "name": "SculptData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Shape", + "children": [ + { + "propertyName": "Relief" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "HeightmapImage" + }, + { + "propertyName": "Edits" + }, + { + "propertyName": "Resolution" + } + ] + }, + { + "folderName": "Layers", + "children": [ + { + "propertyName": "Layer1Color" + }, + { + "propertyName": "Layer1Texture" + }, + { + "propertyName": "Layer1NormalMap" + }, + { + "propertyName": "Layer2Color" + }, + { + "propertyName": "Layer2Texture" + }, + { + "propertyName": "Layer2NormalMap" + }, + { + "propertyName": "Layer3Color" + }, + { + "propertyName": "Layer3Texture" + }, + { + "propertyName": "Layer3NormalMap" + }, + { + "propertyName": "Layer4Color" + }, + { + "propertyName": "Layer4Texture" + }, + { + "propertyName": "Layer4NormalMap" + }, + { + "propertyName": "NormalMapStrength" + }, + { + "propertyName": "TextureSize" + }, + { + "propertyName": "HeightBlending" + }, + { + "propertyName": "TextureVariation" + }, + { + "propertyName": "CliffLayer" + }, + { + "propertyName": "CliffAngle" + } + ] + }, + { + "folderName": "Wetness", + "children": [ + { + "propertyName": "WetShore" + }, + { + "propertyName": "WetShoreZ" + }, + { + "propertyName": "WetShoreFade" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "SculptData" + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 1000, + "areaMaxY": 1000, + "areaMaxZ": 40, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "defaultName": "Grass", + "description": "A field of grass blades swaying in the wind and pushed aside by characters. They grow in the area of the object, on the highest 3D terrain at each point (one field can cover several terrains), or at the Z position of the object where there is no terrain.", + "fullName": "Terrain grass", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0zIDIxYzEtNSAxLTkgMC0xMyAyIDMgMyA3IDMgMTN6bTQgMGMwLTYgMS0xMSA0LTE2LTEgNS0xIDEwIDAgMTZ6bTUgMGMwLTUgMi05IDUtMTItMiA0LTIgOC0xIDEyem01IDBjMS00IDItNiA0LTgtMSAzLTEgNS0xIDh6Ii8+PC9zdmc+", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "TerrainGrass", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/732ef90b7fcf5dd9171fe95d0cf262e09159b487304915a4693baa893d9ce16c_grass.svg", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 1000, + "height": 1000, + "depth": 40, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 40, + "height": 1000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-001000001000", + "width": 1000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineGrassHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainGrass) object.__terrainGrass.dispose();", + "object.__terrainGrass = new gdjs.__terrainGrassExtension.Grass(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "// Time doesn't pass in the scene editor: real time is used to show the wind.", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const time = isInGameEdition", + " ? performance.now() / 1000", + " : object.getRuntimeScene().getTimeManager().getTimeFromStart() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainGrass.update(elapsedTime, time, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainGrass.updateFromProperties();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::TerrainGrass", + "type": "object" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + } + ] + }, + "propertyDescriptors": [ + { + "value": "60", + "type": "Number", + "label": "Density", + "description": "The number of blades in a square of 100 x 100 pixels.", + "group": "Blades", + "name": "Density" + }, + { + "value": "36", + "type": "Number", + "unit": "Pixel", + "label": "Blade height", + "description": "The average height of blades (each blade is between 60% and 140% of it).", + "group": "Blades", + "name": "BladeHeight" + }, + { + "value": "5", + "type": "Number", + "unit": "Pixel", + "label": "Blade width", + "group": "Blades", + "name": "BladeWidth" + }, + { + "value": "52;104;36", + "type": "Color", + "label": "Base color", + "group": "Blades", + "name": "BaseColor" + }, + { + "value": "150;196;82", + "type": "Color", + "label": "Tip color", + "group": "Blades", + "name": "TipColor" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places blades differently.", + "group": "Blades", + "name": "Seed" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, blades only grow where this layer is painted. A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "40", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No blades grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "1", + "type": "Number", + "label": "Wind strength", + "description": "0 for no wind.", + "group": "Wind", + "name": "WindStrength" + }, + { + "value": "2", + "type": "Number", + "label": "Wind speed", + "group": "Wind", + "name": "WindSpeed" + }, + { + "value": "", + "type": "String", + "label": "Object bending the grass", + "description": "The name of an object pushing blades aside when walking through the grass, like the player. The 8 first instances are used.", + "group": "Wind", + "name": "BendingObject" + }, + { + "value": "2500", + "type": "Number", + "unit": "Pixel", + "label": "Fade distance", + "description": "Blades are less and less dense up to this distance from the camera, and hidden after.", + "group": "Rendering", + "name": "FadeDistance" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Blades", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "BladeHeight" + }, + { + "propertyName": "BladeWidth" + }, + { + "propertyName": "BaseColor" + }, + { + "propertyName": "TipColor" + }, + { + "propertyName": "Seed" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + } + ] + }, + { + "folderName": "Wind", + "children": [ + { + "propertyName": "WindStrength" + }, + { + "propertyName": "WindSpeed" + }, + { + "propertyName": "BendingObject" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "FadeDistance" + } + ] + } + ] + }, + "variants": [] + }, + { + "areaMaxX": 2000, + "areaMaxY": 2000, + "areaMaxZ": 200, + "areaMinX": 0, + "areaMinY": 0, + "areaMinZ": 0, + "assetStoreTag": "3d scattered models", + "defaultName": "ScatteredModels", + "description": "Many copies of a 3D model (trees, rocks, bushes, flowers...) placed in the area of the object and drawn all at once, which is much faster than an object for each one. They stand on the highest 3D terrain at each point, or at the Z position of the object where there is no terrain. Paint where they grow with the brushes of the scene editor.", + "fullName": "Scattered models (forests, rocks...)", + "helpPath": "", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGQ9Ik0xMCAyMXYtM0gzbDUtNUg1bDUtNUg3bDUtNSA1IDVoLTNsNSA1aC0zbDUgNWgtN3YzeiIvPjwvc3ZnPg==", + "is3D": true, + "isUsingLegacyInstancesRenderer": true, + "name": "ScatteredModels", + "previewIconUrl": "", + "objects": [ + { + "assetStoreId": "", + "name": "AreaPlaceholder", + "type": "Scene3D::Cube3DObject", + "variables": [], + "effects": [], + "behaviors": [], + "content": { + "width": 2000, + "height": 2000, + "depth": 200, + "enableTextureTransparency": false, + "facesOrientation": "Y", + "backFaceUpThroughWhichAxisRotation": "X", + "materialType": "Basic", + "tint": "255;255;255", + "frontFaceResourceName": "", + "frontFaceVisible": false, + "frontFaceResourceRepeat": false, + "backFaceResourceName": "", + "backFaceVisible": false, + "backFaceResourceRepeat": false, + "leftFaceResourceName": "", + "leftFaceVisible": false, + "leftFaceResourceRepeat": false, + "rightFaceResourceName": "", + "rightFaceVisible": false, + "rightFaceResourceRepeat": false, + "topFaceResourceName": "", + "topFaceVisible": false, + "topFaceResourceRepeat": false, + "bottomFaceResourceName": "", + "bottomFaceVisible": false, + "bottomFaceResourceRepeat": false + } + } + ], + "objectsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "objectName": "AreaPlaceholder" + } + ] + }, + "objectsGroups": [], + "layers": [ + { + "ambientLightColorB": 200, + "ambientLightColorG": 200, + "ambientLightColorR": 200, + "camera2DPlaneMaxDrawingDistance": 5000, + "camera3DFarPlaneDistance": 10000, + "camera3DFieldOfView": 45, + "camera3DNearPlaneDistance": 3, + "cameraType": "", + "followBaseLayerCamera": false, + "isLightingLayer": false, + "isLocked": false, + "name": "", + "renderingType": "", + "visibility": true, + "cameras": [ + { + "defaultSize": true, + "defaultViewport": true, + "height": 0, + "viewportBottom": 1, + "viewportLeft": 0, + "viewportRight": 1, + "viewportTop": 0, + "width": 0 + } + ], + "effects": [] + } + ], + "instances": [ + { + "angle": 0, + "customSize": true, + "depth": 200, + "height": 2000, + "keepRatio": true, + "layer": "", + "name": "AreaPlaceholder", + "persistentUuid": "5d7a8b1e-3c2f-4e6a-9b1d-002000002000", + "width": 2000, + "x": 0, + "y": 0, + "zOrder": 1, + "numberProperties": [], + "stringProperties": [], + "initialVariables": [] + } + ], + "editionSettings": {}, + "eventsFunctions": [ + { + "fullName": "", + "functionType": "Action", + "name": "onCreated", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [], + "actions": [ + { + "type": { + "value": "Terrain3D::DefineScatterHelperClasses" + }, + "parameters": [ + "", + "" + ] + } + ] + }, + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "for (const child of object.getChildrenContainer().getAdhocListOfAllInstances()) {", + " child.deleteFromScene();", + "}", + "if (object.__terrainScatter) object.__terrainScatter.dispose();", + "object.__terrainScatter = new gdjs.__terrainScatterExtension.Scatter(object);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onDestroy", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.dispose();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "doStepPostEvents", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const game = runtimeScene.getGame();", + "const isInGameEdition = game.isInGameEdition && game.isInGameEdition();", + "const elapsedTime = isInGameEdition ? 1 / 60 : object.getElapsedTime() / 1000;", + "const layer = object.getInstanceContainer().getLayer(object.getLayer());", + "object.__terrainScatter.update(elapsedTime, layer.getRenderer().getThreeCamera());" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "fullName": "", + "functionType": "Action", + "name": "onHotReloading", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "object.__terrainScatter.onHotReloading();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "Paint the density of copies around a position, up to the density of the object (copies removed with \"Erase copies\" come back). The effect fades out up to the radius.", + "fullName": "Add copies", + "functionType": "Action", + "group": "Paint", + "name": "AddCopies", + "sentence": "Add copies of _PARAM0_ around _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.addCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "Remove the copies standing in a circle, for example a tree cut by the player (use the position of the nearest copy and a small radius) or a forest cleared for a building. They come back when the scene is restarted.", + "fullName": "Erase copies", + "functionType": "Action", + "group": "Paint", + "name": "EraseCopies", + "sentence": "Erase the copies of _PARAM0_ in a circle at _PARAM1_; _PARAM2_ with a radius of _PARAM3_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const radius = eventsFunctionContext.getArgument(\"Radius\");", + "object.__terrainScatter.removeCopies(x, y, radius);" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position of the center", + "name": "X", + "type": "expression" + }, + { + "description": "Y position of the center", + "name": "Y", + "type": "expression" + }, + { + "description": "Radius", + "name": "Radius", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the number of copies placed in the area.", + "fullName": "Number of copies", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "CopyCount", + "sentence": "the number of copies", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "eventsFunctionContext.returnValue = object.__terrainScatter.getCopyCount();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + } + ], + "objectGroups": [] + }, + { + "description": "The X position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "X position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyX", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.x : x;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Y position of the base of the copy nearest to a position (the position itself if there is no copy).", + "fullName": "Y position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyY", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.y : y;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "The Z position of the base of the copy nearest to a position (on the ground).", + "fullName": "Z position of the nearest copy", + "functionType": "Expression", + "group": "Copies", + "name": "NearestCopyZ", + "sentence": "", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? copy.z : object.getZ();" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + }, + { + "description": "the distance (on X and Y) from a position to the base of the nearest copy. It's a very big number when there is no copy.", + "fullName": "Distance to the nearest copy", + "functionType": "ExpressionAndCondition", + "group": "Copies", + "name": "NearestCopyDistance", + "sentence": "the distance from _PARAM1_; _PARAM2_ to the nearest copy", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "/** @type {gdjs.CustomRuntimeObject3D} */", + "const object = objects[0];", + "const x = eventsFunctionContext.getArgument(\"X\");", + "const y = eventsFunctionContext.getArgument(\"Y\");", + "const copy = object.__terrainScatter.findNearestCopy(x, y);", + "eventsFunctionContext.returnValue = copy ? Math.hypot(copy.x - x, copy.y - y) : Number.MAX_VALUE;" + ], + "parameterObjects": "Object", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "expressionType": { + "type": "expression" + }, + "parameters": [ + { + "description": "Object", + "name": "Object", + "supplementaryInformation": "Terrain3D::ScatteredModels", + "type": "object" + }, + { + "description": "X position", + "name": "X", + "type": "expression" + }, + { + "description": "Y position", + "name": "Y", + "type": "expression" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "onCreated" + }, + { + "functionName": "onDestroy" + }, + { + "functionName": "doStepPostEvents" + }, + { + "functionName": "onHotReloading" + }, + { + "folderName": "Paint", + "children": [ + { + "functionName": "AddCopies" + }, + { + "functionName": "EraseCopies" + } + ] + }, + { + "folderName": "Copies", + "children": [ + { + "functionName": "CopyCount" + }, + { + "functionName": "NearestCopyX" + }, + { + "functionName": "NearestCopyY" + }, + { + "functionName": "NearestCopyZ" + }, + { + "functionName": "NearestCopyDistance" + } + ] + } + ] + }, + "propertyDescriptors": [ + { + "value": "", + "type": "Resource", + "label": "3D model", + "description": "The model copied everywhere (a .glb file). Models standing on the Y axis, like most models of the asset store, are stood up along Z.", + "group": "Model", + "extraInformation": [ + "model3D" + ], + "choices": [], + "name": "Model" + }, + { + "value": "300", + "type": "Number", + "unit": "Pixel", + "label": "Height of a copy", + "description": "Copies keep the proportions of the model.", + "group": "Model", + "name": "Size" + }, + { + "value": "0.8", + "type": "Number", + "label": "Smallest random scale", + "description": "Each copy is scaled at random between the smallest and the largest scale.", + "group": "Model", + "name": "MinScale" + }, + { + "value": "1.2", + "type": "Number", + "label": "Largest random scale", + "group": "Model", + "name": "MaxScale" + }, + { + "value": "true", + "type": "Boolean", + "label": "Random rotation", + "description": "Turn each copy around the Z axis at random.", + "group": "Model", + "name": "RandomRotation" + }, + { + "value": "255;255;255", + "type": "Color", + "label": "Random tint", + "description": "Each copy is tinted between white and this color, at random. White for no tint.", + "group": "Model", + "name": "RandomTint" + }, + { + "value": "0.3", + "type": "Number", + "label": "Density", + "description": "The number of copies in a square of 100 x 100 pixels where the density is fully painted (0.3 is about one copy every 180 pixels). Copies never overlap their neighbors much: they are placed at random in a grid.", + "group": "Placement", + "name": "Density" + }, + { + "value": "1", + "type": "Number", + "label": "Seed", + "description": "Each seed places copies differently.", + "group": "Placement", + "name": "Seed" + }, + { + "value": "Everywhere", + "type": "Choice", + "label": "Copies grow", + "description": "Everywhere in the area, or only where they are painted with the \"Add copies\" brush (or the edits).", + "group": "Placement", + "choices": [ + { + "label": "Everywhere (erase them with the brush)", + "value": "Everywhere" + }, + { + "label": "Only where painted", + "value": "Painted" + } + ], + "name": "Coverage" + }, + { + "value": "1", + "type": "Choice", + "label": "Grows on terrain layer", + "description": "On a 3D terrain, copies only grow where this layer is painted, away from its borders (so that trees don't stand on roads painted with another layer). A new terrain has layer 1 painted everywhere.", + "group": "Ground", + "choices": [ + { + "label": "Any", + "value": "0" + }, + { + "label": "Layer 1", + "value": "1" + }, + { + "label": "Layer 2", + "value": "2" + }, + { + "label": "Layer 3", + "value": "3" + }, + { + "label": "Layer 4", + "value": "4" + } + ], + "name": "GroundLayer" + }, + { + "value": "30", + "type": "Number", + "unit": "DegreeAngle", + "label": "Maximum slope", + "description": "No copies grow on steeper ground.", + "group": "Ground", + "name": "MaxSlope" + }, + { + "value": "-100000", + "type": "Number", + "unit": "Pixel", + "label": "Minimum ground Z", + "description": "No copies grow where the ground is lower (for example, under the water level).", + "group": "Ground", + "name": "MinGroundZ" + }, + { + "value": "100000", + "type": "Number", + "unit": "Pixel", + "label": "Maximum ground Z", + "description": "No copies grow where the ground is higher (for example, above the tree line).", + "group": "Ground", + "name": "MaxGroundZ" + }, + { + "value": "false", + "type": "Boolean", + "label": "Trunk collisions", + "description": "Give each copy a static collision shape around its trunk, for the 3D physics behavior (add it to this object, with the \"Static\" type) and navigation meshes. Without them, these behaviors have no effect on this object.", + "group": "Collisions", + "name": "TrunkCollisions" + }, + { + "value": "30", + "type": "Number", + "unit": "Pixel", + "label": "Trunk diameter", + "description": "The diameter of the collision shape of a copy at the height given in \"Height of a copy\" (it is scaled with the copy).", + "group": "Collisions", + "name": "TrunkDiameter" + }, + { + "value": "8000", + "type": "Number", + "unit": "Pixel", + "label": "Draw distance", + "description": "Copies shrink and are hidden at this distance from the camera.", + "group": "Rendering", + "name": "DrawDistance" + }, + { + "value": "true", + "type": "Boolean", + "label": "Cast shadows", + "group": "Rendering", + "name": "CastShadow" + }, + { + "value": "true", + "type": "Boolean", + "label": "Receive shadows", + "group": "Rendering", + "name": "ReceiveShadow" + }, + { + "value": "", + "type": "MultilineString", + "label": "Edits", + "description": "Where copies are added or erased, applied in order, as a JSON list, for example [{\"tool\": \"add\", \"x\": 0.3, \"y\": 0.4, \"radius\": 0.15}, {\"tool\": \"erase\", \"x\": 0.1, \"y\": 0.9, \"toX\": 0.8, \"toY\": 0.2, \"radius\": 0.02}]. Tools: add (density: from 0 to 1, 1 by default, how dense copies are compared to the Density property) and erase. strength (from 0 to 1) makes a stroke lighter. x, y and radius are fractions (0 to 1) of the object size (x is (scene X - object X) / object width). Add toX and toY to paint along a line (a row of trees, a path through a forest). With \"Copies grow: only where painted\", only the added areas have copies. Shown in the scene editor.", + "group": "Placement", + "advanced": true, + "name": "Edits" + }, + { + "value": "", + "type": "String", + "label": "Painted data", + "description": "Written by the brushes of the scene editor, in a compact format not meant to be read or written by hand: use Edits instead. Clear it to go back to the coverage and the edits.", + "advanced": true, + "name": "PaintData" + } + ], + "propertiesFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "folderName": "Model", + "children": [ + { + "propertyName": "Model" + }, + { + "propertyName": "Size" + }, + { + "propertyName": "MinScale" + }, + { + "propertyName": "MaxScale" + }, + { + "propertyName": "RandomRotation" + }, + { + "propertyName": "RandomTint" + } + ] + }, + { + "folderName": "Placement", + "children": [ + { + "propertyName": "Density" + }, + { + "propertyName": "Seed" + }, + { + "propertyName": "Coverage" + }, + { + "propertyName": "Edits" + } + ] + }, + { + "folderName": "Ground", + "children": [ + { + "propertyName": "GroundLayer" + }, + { + "propertyName": "MaxSlope" + }, + { + "propertyName": "MinGroundZ" + }, + { + "propertyName": "MaxGroundZ" + } + ] + }, + { + "folderName": "Collisions", + "children": [ + { + "propertyName": "TrunkCollisions" + }, + { + "propertyName": "TrunkDiameter" + } + ] + }, + { + "folderName": "Rendering", + "children": [ + { + "propertyName": "DrawDistance" + }, + { + "propertyName": "CastShadow" + }, + { + "propertyName": "ReceiveShadow" + } + ] + }, + { + "propertyName": "PaintData" + } + ] + }, + "variants": [] + } + ] } ], "externalLayouts": [] From d503ef09fc314ca4111fd8ba538e0212ed601090 Mon Sep 17 00:00:00 2001 From: Florian Rival Date: Tue, 3 Nov 2026 00:38:30 +0100 Subject: [PATCH 2/4] Faster 3D terrain in the starters, and fixes for the terrain replacing the ground (#1110) --- .circleci/config.yml | 40 +- .../3d-endless-terrain.json | 122 +- examples/3d-first-person/3d-first-person.json | 122 +- .../3d-island-terrain/3d-island-terrain.json | 158 +- examples/3d-platformer/3d-platformer.json | 233 +- .../3d-shooting-gallery.json | 95 +- .../3d-tile-based-city-builder.json | 95 +- examples/3d-wall-sliding/3d-wall-sliding.json | 95 +- .../platformer-3d-wipeout.json | 122 +- .../starting-3D-platformer.json | 698 +- .../starting-3D-platformer/theme-slots.json | 18 +- .../starting-3d-car-racing.json | 396 +- .../starting-3d-car-racing/theme-slots.json | 14 +- .../starting-3d-driving.json | 396 +- examples/starting-3d-driving/theme-slots.json | 18 +- .../starting-3d-grand-theft-auto.json | 694 +- .../theme-slots.json | 18 +- .../starting-3d-tank/starting-3d-tank.json | 396 +- examples/starting-3d-tank/theme-slots.json | 18 +- .../starting-expanded-3D-platformer.json | 158 +- ...starting-expanded-3d-grand-theft-auto.json | 298 +- .../README.md | 3 + .../assets/Classic Nightstand 01.glb | Bin 0 -> 376928 bytes .../assets/Common Tree Dead 1.glb | Bin 0 -> 128540 bytes .../assets/DarkSkybox_Back.png | Bin 0 -> 109361 bytes .../assets/DarkSkybox_Bottom.png | Bin 0 -> 76396 bytes .../assets/DarkSkybox_Front.png | Bin 0 -> 106227 bytes .../assets/DarkSkybox_Left.png | Bin 0 -> 109309 bytes .../assets/DarkSkybox_Right.png | Bin 0 -> 145006 bytes .../assets/DarkSkybox_Top.png | Bin 0 -> 141982 bytes .../assets/Electric Stove.glb | Bin 0 -> 874008 bytes .../assets/Fence.glb | Bin 0 -> 10272 bytes .../assets/Flat dark joystick border.png | Bin 0 -> 3751 bytes .../assets/Flat dark joystick thumb.png | Bin 0 -> 2939 bytes .../assets/Gothic Bed 01.glb | Bin 0 -> 1174720 bytes .../assets/Gothic Commode 01.glb | Bin 0 -> 546144 bytes .../assets/HouseCeiling.png | Bin 0 -> 23251 bytes .../assets/HouseCrate.png | Bin 0 -> 194982 bytes .../assets/HouseDoor.png | Bin 0 -> 74740 bytes .../assets/HouseFloor.png | Bin 0 -> 159974 bytes .../assets/HouseRoof.png | Bin 0 -> 170763 bytes .../assets/HouseSiding.png | Bin 0 -> 237437 bytes .../assets/HouseWallpaper.png | Bin 0 -> 233923 bytes .../assets/HouseYard.png | Bin 0 -> 112105 bytes .../assets/Key.glb | Bin 0 -> 12400 bytes .../assets/NotoSansArabicUI-Black.ttf | Bin 0 -> 338040 bytes .../assets/Ornate Mirror 01.glb | Bin 0 -> 709384 bytes .../assets/Painted Wooden Cabinet 02.glb | Bin 0 -> 321908 bytes .../assets/Painted Wooden Cabinet.glb | Bin 0 -> 443368 bytes .../assets/Painted Wooden Chair 02.glb | Bin 0 -> 494368 bytes .../assets/Rock Moss 1.glb | Bin 0 -> 5676 bytes .../assets/Rock Moss 4.glb | Bin 0 -> 9044 bytes .../assets/Rockingchair 01.glb | Bin 0 -> 810276 bytes .../assets/Small Wooden Table 01.glb | Bin 0 -> 388648 bytes .../assets/Sofa 03.glb | Bin 0 -> 656780 bytes .../assets/StarterGlass.png | Bin 0 -> 2774 bytes .../assets/StarterToggle_Keyboard.png | Bin 0 -> 3413 bytes .../assets/StarterToggle_Touch.png | Bin 0 -> 3329 bytes .../assets/Street Lamp 01.glb | Bin 0 -> 1187772 bytes .../assets/Television 01.glb | Bin 0 -> 460292 bytes .../assets/Top arrow button.png | Bin 0 -> 3635 bytes .../assets/Vintage Day Bed.glb | Bin 0 -> 578220 bytes .../assets/Vintage Grandfather Clock 01.glb | Bin 0 -> 825176 bytes .../assets/Vintage Oil Lamp.glb | Bin 0 -> 671852 bytes .../assets/Willow Dead 1.glb | Bin 0 -> 63352 bytes .../assets/Wooden Bookshelf Worn.glb | Bin 0 -> 888688 bytes .../assets/Wooden Table 01.glb | Bin 0 -> 464276 bytes .../assets/Worn Metal Rack.glb | Bin 0 -> 628128 bytes .../assets/starting_unit_character_orange.glb | Bin 0 -> 35872 bytes .../preview.png | Bin 0 -> 303682 bytes .../starting-expanded-3d-house-horror.json | 37710 ++++++++++++++++ .../theme-slots.json | 64 + .../thumbnail.png | Bin 0 -> 907143 bytes ...tarting-expanded-first-person-farming.json | 158 +- ...starting-expanded-first-person-horror.json | 158 +- ...expanded-first-person-shooter-enemies.json | 468 +- ...-expanded-first-person-shooter-horror.json | 468 +- ...panded-first-person-survival-crafting.json | 158 +- .../starting-first-person-farming.json | 746 +- .../theme-slots.json | 12 +- .../starting-first-person-horror.json | 698 +- .../theme-slots.json | 16 +- ...starting-first-person-shooter-enemies.json | 871 +- .../theme-slots.json | 16 +- .../starting-first-person-shooter-horror.json | 1008 +- .../theme-slots.json | 16 +- .../starting-first-person-shooter.json | 1008 +- .../theme-slots.json | 16 +- ...arting-first-person-survival-crafting.json | 746 +- .../theme-slots.json | 16 +- .../starting-first-person.json | 698 +- .../starting-first-person/theme-slots.json | 16 +- 92 files changed, 45648 insertions(+), 3626 deletions(-) create mode 100644 examples/starting-expanded-3d-house-horror/README.md create mode 100644 examples/starting-expanded-3d-house-horror/assets/Classic Nightstand 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Common Tree Dead 1.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Back.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Bottom.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Front.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Left.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Right.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Top.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/Electric Stove.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Fence.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Flat dark joystick border.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/Flat dark joystick thumb.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/Gothic Bed 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Gothic Commode 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/HouseCeiling.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/HouseCrate.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/HouseDoor.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/HouseFloor.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/HouseRoof.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/HouseSiding.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/HouseWallpaper.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/HouseYard.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/Key.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/NotoSansArabicUI-Black.ttf create mode 100644 examples/starting-expanded-3d-house-horror/assets/Ornate Mirror 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Painted Wooden Cabinet 02.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Painted Wooden Cabinet.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Painted Wooden Chair 02.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Rock Moss 1.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Rock Moss 4.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Rockingchair 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Small Wooden Table 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Sofa 03.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/StarterGlass.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/StarterToggle_Keyboard.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/StarterToggle_Touch.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/Street Lamp 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Television 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Top arrow button.png create mode 100644 examples/starting-expanded-3d-house-horror/assets/Vintage Day Bed.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Vintage Grandfather Clock 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Vintage Oil Lamp.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Willow Dead 1.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Wooden Bookshelf Worn.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Wooden Table 01.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/Worn Metal Rack.glb create mode 100644 examples/starting-expanded-3d-house-horror/assets/starting_unit_character_orange.glb create mode 100644 examples/starting-expanded-3d-house-horror/preview.png create mode 100644 examples/starting-expanded-3d-house-horror/starting-expanded-3d-house-horror.json create mode 100644 examples/starting-expanded-3d-house-horror/theme-slots.json create mode 100644 examples/starting-expanded-3d-house-horror/thumbnail.png diff --git a/.circleci/config.yml b/.circleci/config.yml index 4887a5051..c66f88d0e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,12 +33,38 @@ jobs: - checkout - run: npm install - run: git clone git@github.com:4ian/GDevelop.git --depth 1 - - run: cd GDevelop/newIDE/app && npm install + - run: + name: Generate the cache key of GDevelop dependencies + # Computed before the install, which can rewrite the lock files. + command: cat GDevelop/newIDE/app/package-lock.json GDevelop/GDJS/package-lock.json | shasum -a 256 > gdevelop-dependencies-checksum.txt + - restore_cache: + keys: + - gdevelop-dependencies-v1-{{ checksum "gdevelop-dependencies-checksum.txt" }} + # fallback to using the latest cache if no exact match is found + - gdevelop-dependencies-v1- + - run: cd GDevelop/newIDE/app && npm install --no-audit --no-fund + - save_cache: + paths: + - GDevelop/newIDE/app/node_modules + - GDevelop/GDJS/node_modules + key: gdevelop-dependencies-v1-{{ checksum "gdevelop-dependencies-checksum.txt" }} - persist_to_workspace: root: . paths: - node_modules # For npm install. - - GDevelop/newIDE/app # As we have a dependency on GDevelop sources. + # What scripts/lib/GDevelopCoreLoader.js loads from GDevelop (not the + # whole newIDE/app: its node_modules are more than 1GB, long to persist + # and to attach in every job). + # Without it, the files of GDevelop would take the "type" of the + # package.json of this repository. + - GDevelop/newIDE/app/package.json + - GDevelop/newIDE/app/public/libGD.js + - GDevelop/newIDE/app/public/libGD.wasm + - GDevelop/newIDE/app/resources/GDJS + - GDevelop/newIDE/app/src + # The packages required by newIDE/app/src/JsExtensionsLoader. + - GDevelop/newIDE/app/node_modules/lodash + - GDevelop/newIDE/app/node_modules/node-require-function tests: docker: - image: cimg/node:20.13.1 @@ -77,6 +103,11 @@ jobs: - attach_workspace: at: . - aws-cli/setup + - run: + # The deploy uploads more than a thousand small files: the default of + # 10 concurrent requests makes it take minutes. + name: Upload more files in parallel + command: aws configure set default.s3.max_concurrent_requests 64 - run: npm run deploy -- --cf-zoneid $CLOUDFLARE_ZONE_ID --cf-token $CLOUDFLARE_TOKEN deploy-staging: docker: @@ -94,6 +125,11 @@ jobs: - attach_workspace: at: . - aws-cli/setup + - run: + # The deploy uploads more than a thousand small files: the default of + # 10 concurrent requests makes it take minutes. + name: Upload more files in parallel + command: aws configure set default.s3.max_concurrent_requests 64 - run: npm run deploy -- --staging --cf-zoneid $CLOUDFLARE_ZONE_ID --cf-token $CLOUDFLARE_TOKEN # Run the gameplay tests of the example games with a real GDevelop: the diff --git a/examples/3d-endless-terrain/3d-endless-terrain.json b/examples/3d-endless-terrain/3d-endless-terrain.json index 2377883a4..b9ba18f03 100644 --- a/examples/3d-endless-terrain/3d-endless-terrain.json +++ b/examples/3d-endless-terrain/3d-endless-terrain.json @@ -8498,8 +8498,8 @@ "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBvbHlsaW5lIGNsYXNzPSJzdDAiIHBvaW50cz0iMTksMTkgMjQsMTkgMjQsMjQgIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSI2LDIzIDExLDIzIDExLDE4ICIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI0LDE5LjRjLTAuNywwLjgtMS40LDEuNi0yLjIsMi40Yy03LDctMTUuMywxMC4yLTE4LjUsN3MtMC4xLTExLjUsNy0xOC41czE1LjMtMTAuMiwxOC41LTcNCgljMS40LDEuNCwxLjYsMy42LDAuOCw2LjMiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwyMi41Yy0wLjMtMC4yLTAuNS0wLjUtMC44LTAuOGMtNy03LTEwLjItMTUuMy03LTE4LjVzMTEuNS0wLjEsMTguNSw3czEwLjIsMTUuMyw3LDE4LjUNCgljLTEuNywxLjctNC44LDEuNi04LjQsMC4xIi8+DQo8L3N2Zz4NCg==", "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", - "shortDescription": "This behavior removes the limit on the distance the mouse can move and hides the cursor.", - "version": "0.3.0", + "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -8547,7 +8547,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -8795,16 +8795,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -8951,7 +8981,7 @@ "functionType": "Condition", "name": "isEmulatingPointerLock", "private": true, - "sentence": "The mouse pointer is lock is emulated", + "sentence": "The mouse pointer lock is emulated", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -8987,6 +9017,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -9293,6 +9348,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -9314,7 +9381,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { @@ -9957,32 +10024,7 @@ "name": "ShouldLock" } ], - "propertiesFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "propertyName": "Object3D" - }, - { - "propertyName": "HorizontalSpeed" - }, - { - "propertyName": "VerticalSpeed" - }, - { - "propertyName": "VerticalAngleMin" - }, - { - "propertyName": "VerticalAngleMax" - }, - { - "propertyName": "OffsetZ" - }, - { - "propertyName": "ShouldLock" - } - ] - } + "sharedPropertyDescriptors": [] } ], "eventsBasedObjects": [] diff --git a/examples/3d-first-person/3d-first-person.json b/examples/3d-first-person/3d-first-person.json index 2bbcc98eb..74f7fec7e 100644 --- a/examples/3d-first-person/3d-first-person.json +++ b/examples/3d-first-person/3d-first-person.json @@ -3356,8 +3356,8 @@ "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBvbHlsaW5lIGNsYXNzPSJzdDAiIHBvaW50cz0iMTksMTkgMjQsMTkgMjQsMjQgIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSI2LDIzIDExLDIzIDExLDE4ICIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI0LDE5LjRjLTAuNywwLjgtMS40LDEuNi0yLjIsMi40Yy03LDctMTUuMywxMC4yLTE4LjUsN3MtMC4xLTExLjUsNy0xOC41czE1LjMtMTAuMiwxOC41LTcNCgljMS40LDEuNCwxLjYsMy42LDAuOCw2LjMiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwyMi41Yy0wLjMtMC4yLTAuNS0wLjUtMC44LTAuOGMtNy03LTEwLjItMTUuMy03LTE4LjVzMTEuNS0wLjEsMTguNSw3czEwLjIsMTUuMyw3LDE4LjUNCgljLTEuNywxLjctNC44LDEuNi04LjQsMC4xIi8+DQo8L3N2Zz4NCg==", "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", - "shortDescription": "This behavior removes the limit on the distance the mouse can move and hides the cursor.", - "version": "0.3.0", + "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -3405,7 +3405,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -3653,16 +3653,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -3809,7 +3839,7 @@ "functionType": "Condition", "name": "isEmulatingPointerLock", "private": true, - "sentence": "The mouse pointer is lock is emulated", + "sentence": "The mouse pointer lock is emulated", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -3845,6 +3875,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -4151,6 +4206,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -4172,7 +4239,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { @@ -4815,32 +4882,7 @@ "name": "ShouldLock" } ], - "propertiesFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "propertyName": "Object3D" - }, - { - "propertyName": "HorizontalSpeed" - }, - { - "propertyName": "VerticalSpeed" - }, - { - "propertyName": "VerticalAngleMin" - }, - { - "propertyName": "VerticalAngleMax" - }, - { - "propertyName": "OffsetZ" - }, - { - "propertyName": "ShouldLock" - } - ] - } + "sharedPropertyDescriptors": [] } ], "eventsBasedObjects": [] diff --git a/examples/3d-island-terrain/3d-island-terrain.json b/examples/3d-island-terrain/3d-island-terrain.json index 705fee01a..0b24084dc 100644 --- a/examples/3d-island-terrain/3d-island-terrain.json +++ b/examples/3d-island-terrain/3d-island-terrain.json @@ -2164,6 +2164,51 @@ "source": "", "type": "BuiltinCommonInstructions::Group", "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Start with touch controls on touchscreens." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SceneJustBegins" + }, + "parameters": [ + "" + ] + }, + { + "type": { + "value": "SystemInfo::HasTouchScreen" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SpriteToggleSwitch::SpriteToggleSwitch::SetChecked" + }, + "parameters": [ + "ControlsToggle", + "yes", + "" + ] + } + ] + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -2710,18 +2755,11 @@ "conditions": [ { "type": { - "value": "MouseButtonFromTextPressed" + "value": "HasAnyTouchOrMouseStarted" }, "parameters": [ - "", - "\"Left\"" + "" ] - }, - { - "type": { - "value": "BuiltinCommonInstructions::Once" - }, - "parameters": [] } ], "actions": [], @@ -2740,17 +2778,6 @@ "\"Left\"", "" ] - }, - { - "type": { - "inverted": true, - "value": "SpriteMultitouchJoystick::MultitouchButton::IsPressed" - }, - "parameters": [ - "JumpButton", - "MultitouchButton", - "" - ] } ], "actions": [ @@ -17239,7 +17266,7 @@ "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", - "version": "0.3.1", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -17287,7 +17314,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -17535,16 +17562,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -17727,6 +17784,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -18033,6 +18115,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -18054,7 +18148,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { diff --git a/examples/3d-platformer/3d-platformer.json b/examples/3d-platformer/3d-platformer.json index 15c192026..91ee83401 100644 --- a/examples/3d-platformer/3d-platformer.json +++ b/examples/3d-platformer/3d-platformer.json @@ -19919,7 +19919,6 @@ { "author": "PANDAKO-GitHub", "category": "Input", - "dimension": "", "extensionNamespace": "", "fullName": "Mouse Pointer Lock", "gdevelopVersion": ">=5.5.222", @@ -19927,8 +19926,8 @@ "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBvbHlsaW5lIGNsYXNzPSJzdDAiIHBvaW50cz0iMTksMTkgMjQsMTkgMjQsMjQgIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSI2LDIzIDExLDIzIDExLDE4ICIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI0LDE5LjRjLTAuNywwLjgtMS40LDEuNi0yLjIsMi40Yy03LDctMTUuMywxMC4yLTE4LjUsN3MtMC4xLTExLjUsNy0xOC41czE1LjMtMTAuMiwxOC41LTcNCgljMS40LDEuNCwxLjYsMy42LDAuOCw2LjMiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwyMi41Yy0wLjMtMC4yLTAuNS0wLjUtMC44LTAuOGMtNy03LTEwLjItMTUuMy03LTE4LjVzMTEuNS0wLjEsMTguNSw3czEwLjIsMTUuMyw3LDE4LjUNCgljLTEuNywxLjctNC44LDEuNi04LjQsMC4xIi8+DQo8L3N2Zz4NCg==", "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", - "shortDescription": "This behavior removes the limit on the distance the mouse can move and hides the cursor.", - "version": "0.3.0", + "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -19976,7 +19975,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -20224,16 +20223,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -20416,6 +20445,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -20697,68 +20751,12 @@ "objectGroups": [] } ], - "eventsFunctionsFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "functionName": "onFirstSceneLoaded" - }, - { - "functionName": "onScenePostEvents" - }, - { - "functionName": "RequestPointerLock" - }, - { - "functionName": "ExitPointerLock" - }, - { - "functionName": "isPointerLocked" - }, - { - "functionName": "isPointerActuallyLocked" - }, - { - "functionName": "isEmulatingPointerLock" - }, - { - "functionName": "IsMoving" - }, - { - "functionName": "MovementX" - }, - { - "functionName": "SetMovementX" - }, - { - "functionName": "MovementY" - }, - { - "functionName": "SetMovementY" - }, - { - "functionName": "TouchX" - }, - { - "functionName": "TouchY" - }, - { - "functionName": "TouchSpeedFactor" - }, - { - "functionName": "SetTouchSpeedFactor" - } - ] - }, "eventsBasedBehaviors": [ { "description": "Control camera rotations with a mouse.", "fullName": "First person camera mouse mapper", - "helpPath": "", - "iconUrl": "", "name": "FirstPersonPointerMapper", "objectType": "", - "previewIconUrl": "", "eventsFunctions": [ { "fullName": "", @@ -20778,6 +20776,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -20799,7 +20809,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { @@ -21033,7 +21043,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "HorizontalSpeed", - "group": "First person camera mouse mapper configuration", "name": "SetHorizontalSpeed", "sentence": "", "events": [ @@ -21114,7 +21123,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalSpeed", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalSpeed", "sentence": "", "events": [ @@ -21195,7 +21203,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMin", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMin", "sentence": "", "events": [ @@ -21276,7 +21283,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMax", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMax", "sentence": "", "events": [ @@ -21357,7 +21363,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "OffsetZ", - "group": "First person camera mouse mapper configuration", "name": "SetOffsetZ", "sentence": "", "events": [ @@ -21394,57 +21399,6 @@ "objectGroups": [] } ], - "eventsFunctionsFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "functionName": "doStepPreEvents" - }, - { - "folderName": "Layers and cameras", - "children": [ - { - "functionName": "LookFromObjectEyes" - } - ] - }, - { - "folderName": "First person camera mouse mapper configuration", - "children": [ - { - "functionName": "HorizontalSpeed" - }, - { - "functionName": "SetHorizontalSpeed" - }, - { - "functionName": "VerticalSpeed" - }, - { - "functionName": "SetVerticalSpeed" - }, - { - "functionName": "VerticalAngleMin" - }, - { - "functionName": "SetVerticalAngleMin" - }, - { - "functionName": "VerticalAngleMax" - }, - { - "functionName": "SetVerticalAngleMax" - }, - { - "functionName": "OffsetZ" - }, - { - "functionName": "SetOffsetZ" - } - ] - } - ] - }, "propertyDescriptors": [ { "value": "", @@ -21498,32 +21452,7 @@ "name": "ShouldLock" } ], - "propertiesFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "propertyName": "Object3D" - }, - { - "propertyName": "HorizontalSpeed" - }, - { - "propertyName": "VerticalSpeed" - }, - { - "propertyName": "VerticalAngleMin" - }, - { - "propertyName": "VerticalAngleMax" - }, - { - "propertyName": "OffsetZ" - }, - { - "propertyName": "ShouldLock" - } - ] - } + "sharedPropertyDescriptors": [] } ], "eventsBasedObjects": [] diff --git a/examples/3d-shooting-gallery/3d-shooting-gallery.json b/examples/3d-shooting-gallery/3d-shooting-gallery.json index 4444bba1b..3fd54aa75 100644 --- a/examples/3d-shooting-gallery/3d-shooting-gallery.json +++ b/examples/3d-shooting-gallery/3d-shooting-gallery.json @@ -11666,8 +11666,8 @@ "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBvbHlsaW5lIGNsYXNzPSJzdDAiIHBvaW50cz0iMTksMTkgMjQsMTkgMjQsMjQgIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSI2LDIzIDExLDIzIDExLDE4ICIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI0LDE5LjRjLTAuNywwLjgtMS40LDEuNi0yLjIsMi40Yy03LDctMTUuMywxMC4yLTE4LjUsN3MtMC4xLTExLjUsNy0xOC41czE1LjMtMTAuMiwxOC41LTcNCgljMS40LDEuNCwxLjYsMy42LDAuOCw2LjMiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwyMi41Yy0wLjMtMC4yLTAuNS0wLjUtMC44LTAuOGMtNy03LTEwLjItMTUuMy03LTE4LjVzMTEuNS0wLjEsMTguNSw3czEwLjIsMTUuMyw3LDE4LjUNCgljLTEuNywxLjctNC44LDEuNi04LjQsMC4xIi8+DQo8L3N2Zz4NCg==", "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", - "shortDescription": "This behavior removes the limit on the distance the mouse can move and hides the cursor.", - "version": "0.3.0", + "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -11715,7 +11715,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -11963,16 +11963,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -12119,7 +12149,7 @@ "functionType": "Condition", "name": "isEmulatingPointerLock", "private": true, - "sentence": "The mouse pointer is lock is emulated", + "sentence": "The mouse pointer lock is emulated", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -12155,6 +12185,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -12461,6 +12516,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -12482,7 +12549,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { diff --git a/examples/3d-tile-based-city-builder/3d-tile-based-city-builder.json b/examples/3d-tile-based-city-builder/3d-tile-based-city-builder.json index 6bc9b62fe..500effaf1 100644 --- a/examples/3d-tile-based-city-builder/3d-tile-based-city-builder.json +++ b/examples/3d-tile-based-city-builder/3d-tile-based-city-builder.json @@ -2074,8 +2074,8 @@ "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBvbHlsaW5lIGNsYXNzPSJzdDAiIHBvaW50cz0iMTksMTkgMjQsMTkgMjQsMjQgIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSI2LDIzIDExLDIzIDExLDE4ICIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI0LDE5LjRjLTAuNywwLjgtMS40LDEuNi0yLjIsMi40Yy03LDctMTUuMywxMC4yLTE4LjUsN3MtMC4xLTExLjUsNy0xOC41czE1LjMtMTAuMiwxOC41LTcNCgljMS40LDEuNCwxLjYsMy42LDAuOCw2LjMiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwyMi41Yy0wLjMtMC4yLTAuNS0wLjUtMC44LTAuOGMtNy03LTEwLjItMTUuMy03LTE4LjVzMTEuNS0wLjEsMTguNSw3czEwLjIsMTUuMyw3LDE4LjUNCgljLTEuNywxLjctNC44LDEuNi04LjQsMC4xIi8+DQo8L3N2Zz4NCg==", "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", - "shortDescription": "This behavior removes the limit on the distance the mouse can move and hides the cursor.", - "version": "0.3.0", + "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -2123,7 +2123,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -2371,16 +2371,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -2527,7 +2557,7 @@ "functionType": "Condition", "name": "isEmulatingPointerLock", "private": true, - "sentence": "The mouse pointer is lock is emulated", + "sentence": "The mouse pointer lock is emulated", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -2563,6 +2593,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -2869,6 +2924,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -2890,7 +2957,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { diff --git a/examples/3d-wall-sliding/3d-wall-sliding.json b/examples/3d-wall-sliding/3d-wall-sliding.json index 859560a58..a96e2b495 100644 --- a/examples/3d-wall-sliding/3d-wall-sliding.json +++ b/examples/3d-wall-sliding/3d-wall-sliding.json @@ -3714,8 +3714,8 @@ "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBvbHlsaW5lIGNsYXNzPSJzdDAiIHBvaW50cz0iMTksMTkgMjQsMTkgMjQsMjQgIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSI2LDIzIDExLDIzIDExLDE4ICIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI0LDE5LjRjLTAuNywwLjgtMS40LDEuNi0yLjIsMi40Yy03LDctMTUuMywxMC4yLTE4LjUsN3MtMC4xLTExLjUsNy0xOC41czE1LjMtMTAuMiwxOC41LTcNCgljMS40LDEuNCwxLjYsMy42LDAuOCw2LjMiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwyMi41Yy0wLjMtMC4yLTAuNS0wLjUtMC44LTAuOGMtNy03LTEwLjItMTUuMy03LTE4LjVzMTEuNS0wLjEsMTguNSw3czEwLjIsMTUuMyw3LDE4LjUNCgljLTEuNywxLjctNC44LDEuNi04LjQsMC4xIi8+DQo8L3N2Zz4NCg==", "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", - "shortDescription": "This behavior removes the limit on the distance the mouse can move and hides the cursor.", - "version": "0.3.0", + "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -3763,7 +3763,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -4011,16 +4011,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -4167,7 +4197,7 @@ "functionType": "Condition", "name": "isEmulatingPointerLock", "private": true, - "sentence": "The mouse pointer is lock is emulated", + "sentence": "The mouse pointer lock is emulated", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -4203,6 +4233,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -4509,6 +4564,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -4530,7 +4597,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { diff --git a/examples/platformer-3d-wipeout/platformer-3d-wipeout.json b/examples/platformer-3d-wipeout/platformer-3d-wipeout.json index 14be783a7..0c0234bee 100644 --- a/examples/platformer-3d-wipeout/platformer-3d-wipeout.json +++ b/examples/platformer-3d-wipeout/platformer-3d-wipeout.json @@ -11475,8 +11475,8 @@ "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBvbHlsaW5lIGNsYXNzPSJzdDAiIHBvaW50cz0iMTksMTkgMjQsMTkgMjQsMjQgIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSI2LDIzIDExLDIzIDExLDE4ICIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI0LDE5LjRjLTAuNywwLjgtMS40LDEuNi0yLjIsMi40Yy03LDctMTUuMywxMC4yLTE4LjUsN3MtMC4xLTExLjUsNy0xOC41czE1LjMtMTAuMiwxOC41LTcNCgljMS40LDEuNCwxLjYsMy42LDAuOCw2LjMiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwyMi41Yy0wLjMtMC4yLTAuNS0wLjUtMC44LTAuOGMtNy03LTEwLjItMTUuMy03LTE4LjVzMTEuNS0wLjEsMTguNSw3czEwLjIsMTUuMyw3LDE4LjUNCgljLTEuNywxLjctNC44LDEuNi04LjQsMC4xIi8+DQo8L3N2Zz4NCg==", "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", - "shortDescription": "This behavior removes the limit on the distance the mouse can move and hides the cursor.", - "version": "0.3.0", + "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -11524,7 +11524,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -11772,16 +11772,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -11928,7 +11958,7 @@ "functionType": "Condition", "name": "isEmulatingPointerLock", "private": true, - "sentence": "The mouse pointer is lock is emulated", + "sentence": "The mouse pointer lock is emulated", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -11964,6 +11994,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -12270,6 +12325,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -12291,7 +12358,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { @@ -12934,32 +13001,7 @@ "name": "ShouldLock" } ], - "propertiesFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "propertyName": "Object3D" - }, - { - "propertyName": "HorizontalSpeed" - }, - { - "propertyName": "VerticalSpeed" - }, - { - "propertyName": "VerticalAngleMin" - }, - { - "propertyName": "VerticalAngleMax" - }, - { - "propertyName": "OffsetZ" - }, - { - "propertyName": "ShouldLock" - } - ] - } + "sharedPropertyDescriptors": [] } ], "eventsBasedObjects": [] diff --git a/examples/starting-3D-platformer/starting-3D-platformer.json b/examples/starting-3D-platformer/starting-3D-platformer.json index 3b068b660..2a2afb982 100644 --- a/examples/starting-3D-platformer/starting-3D-platformer.json +++ b/examples/starting-3D-platformer/starting-3D-platformer.json @@ -1517,6 +1517,51 @@ "source": "", "type": "BuiltinCommonInstructions::Group", "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Start with touch controls on touchscreens." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SceneJustBegins" + }, + "parameters": [ + "" + ] + }, + { + "type": { + "value": "SystemInfo::HasTouchScreen" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SpriteToggleSwitch::SpriteToggleSwitch::SetChecked" + }, + "parameters": [ + "ControlsToggle", + "yes", + "" + ] + } + ] + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -2063,18 +2108,11 @@ "conditions": [ { "type": { - "value": "MouseButtonFromTextPressed" + "value": "HasAnyTouchOrMouseStarted" }, "parameters": [ - "", - "\"Left\"" + "" ] - }, - { - "type": { - "value": "BuiltinCommonInstructions::Once" - }, - "parameters": [] } ], "actions": [], @@ -2093,17 +2131,6 @@ "\"Left\"", "" ] - }, - { - "type": { - "inverted": true, - "value": "SpriteMultitouchJoystick::MultitouchButton::IsPressed" - }, - "parameters": [ - "JumpButton", - "MultitouchButton", - "" - ] } ], "actions": [ @@ -15268,7 +15295,6 @@ { "author": "PANDAKO-GitHub", "category": "Input", - "dimension": "", "extensionNamespace": "", "fullName": "Mouse Pointer Lock", "gdevelopVersion": ">=5.5.222", @@ -15276,8 +15302,8 @@ "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAyMy4wLjMsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iSWNvbnMiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzIgMzIiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDMyIDMyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDoxMDt9DQo8L3N0eWxlPg0KPHBvbHlsaW5lIGNsYXNzPSJzdDAiIHBvaW50cz0iMTksMTkgMjQsMTkgMjQsMjQgIi8+DQo8cG9seWxpbmUgY2xhc3M9InN0MCIgcG9pbnRzPSI2LDIzIDExLDIzIDExLDE4ICIvPg0KPHBhdGggY2xhc3M9InN0MCIgZD0iTTI0LDE5LjRjLTAuNywwLjgtMS40LDEuNi0yLjIsMi40Yy03LDctMTUuMywxMC4yLTE4LjUsN3MtMC4xLTExLjUsNy0xOC41czE1LjMtMTAuMiwxOC41LTcNCgljMS40LDEuNCwxLjYsMy42LDAuOCw2LjMiLz4NCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik0xMSwyMi41Yy0wLjMtMC4yLTAuNS0wLjUtMC44LTAuOGMtNy03LTEwLjItMTUuMy03LTE4LjVzMTEuNS0wLjEsMTguNSw3czEwLjIsMTUuMyw3LDE4LjUNCgljLTEuNywxLjctNC44LDEuNi04LjQsMC4xIi8+DQo8L3N2Zz4NCg==", "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", - "shortDescription": "This behavior removes the limit on the distance the mouse can move and hides the cursor.", - "version": "0.3.0", + "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -15325,7 +15351,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -15573,16 +15599,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -15729,7 +15785,7 @@ "functionType": "Condition", "name": "isEmulatingPointerLock", "private": true, - "sentence": "The mouse pointer is lock is emulated", + "sentence": "The mouse pointer lock is emulated", "events": [ { "type": "BuiltinCommonInstructions::Standard", @@ -15765,6 +15821,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -16046,68 +16127,12 @@ "objectGroups": [] } ], - "eventsFunctionsFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "functionName": "onFirstSceneLoaded" - }, - { - "functionName": "onScenePostEvents" - }, - { - "functionName": "RequestPointerLock" - }, - { - "functionName": "ExitPointerLock" - }, - { - "functionName": "isPointerLocked" - }, - { - "functionName": "isPointerActuallyLocked" - }, - { - "functionName": "isEmulatingPointerLock" - }, - { - "functionName": "IsMoving" - }, - { - "functionName": "MovementX" - }, - { - "functionName": "SetMovementX" - }, - { - "functionName": "MovementY" - }, - { - "functionName": "SetMovementY" - }, - { - "functionName": "TouchX" - }, - { - "functionName": "TouchY" - }, - { - "functionName": "TouchSpeedFactor" - }, - { - "functionName": "SetTouchSpeedFactor" - } - ] - }, "eventsBasedBehaviors": [ { "description": "Control camera rotations with a mouse.", "fullName": "First person camera mouse mapper", - "helpPath": "", - "iconUrl": "", "name": "FirstPersonPointerMapper", "objectType": "", - "previewIconUrl": "", "eventsFunctions": [ { "fullName": "", @@ -16127,6 +16152,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -16148,7 +16185,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { @@ -16382,7 +16419,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "HorizontalSpeed", - "group": "First person camera mouse mapper configuration", "name": "SetHorizontalSpeed", "sentence": "", "events": [ @@ -16463,7 +16499,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalSpeed", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalSpeed", "sentence": "", "events": [ @@ -16544,7 +16579,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMin", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMin", "sentence": "", "events": [ @@ -16625,7 +16659,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMax", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMax", "sentence": "", "events": [ @@ -16706,7 +16739,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "OffsetZ", - "group": "First person camera mouse mapper configuration", "name": "SetOffsetZ", "sentence": "", "events": [ @@ -16743,57 +16775,6 @@ "objectGroups": [] } ], - "eventsFunctionsFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "functionName": "doStepPreEvents" - }, - { - "folderName": "Layers and cameras", - "children": [ - { - "functionName": "LookFromObjectEyes" - } - ] - }, - { - "folderName": "First person camera mouse mapper configuration", - "children": [ - { - "functionName": "HorizontalSpeed" - }, - { - "functionName": "SetHorizontalSpeed" - }, - { - "functionName": "VerticalSpeed" - }, - { - "functionName": "SetVerticalSpeed" - }, - { - "functionName": "VerticalAngleMin" - }, - { - "functionName": "SetVerticalAngleMin" - }, - { - "functionName": "VerticalAngleMax" - }, - { - "functionName": "SetVerticalAngleMax" - }, - { - "functionName": "OffsetZ" - }, - { - "functionName": "SetOffsetZ" - } - ] - } - ] - }, "propertyDescriptors": [ { "value": "", @@ -16847,32 +16828,7 @@ "name": "ShouldLock" } ], - "propertiesFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "propertyName": "Object3D" - }, - { - "propertyName": "HorizontalSpeed" - }, - { - "propertyName": "VerticalSpeed" - }, - { - "propertyName": "VerticalAngleMin" - }, - { - "propertyName": "VerticalAngleMax" - }, - { - "propertyName": "OffsetZ" - }, - { - "propertyName": "ShouldLock" - } - ] - } + "sharedPropertyDescriptors": [] } ], "eventsBasedObjects": [] @@ -27659,7 +27615,7 @@ "name": "Terrain3D", "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", - "version": "0.1.0", + "version": "0.2.0", "description": [ "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", "", @@ -28759,8 +28715,17 @@ "vTerrainLocalXY = position.xy;", "vTerrainLocalZ = position.z;", "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", - "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "// The world normal, from the camera space normal (computed by Three.js with a", + "// matrix inverted on the CPU), instead of inverting a matrix for each vertex.", + "vTerrainUp = inverseTransformDirection(transformedNormal, viewMatrix).z;", "`;", + "/** @param {(layer: number) => string} getLayerCode */", + "const forEachLayerCode = (getLayerCode) => [0, 1, 2, 3].map(getLayerCode).join('\\n');", + "", + "// Noise is read from a texture of random values, repeated every", + "// NOISE_MAP_SIZE units of noise: 1 texture read instead of 16 hashes.", + "const NOISE_MAP_SIZE = 256;", + "", "const fragmentShaderDeclarations = `", "uniform sampler2D terrainSplatMap;", "uniform vec2 terrainSplatUvScaleAndOffset;", @@ -28769,11 +28734,11 @@ "uniform sampler2D terrainLayerMap1;", "uniform sampler2D terrainLayerMap2;", "uniform sampler2D terrainLayerMap3;", + "uniform vec3 terrainLayerAverageColors[4];", "uniform sampler2D terrainLayerNormalMap0;", "uniform sampler2D terrainLayerNormalMap1;", "uniform sampler2D terrainLayerNormalMap2;", "uniform sampler2D terrainLayerNormalMap3;", - "uniform float terrainHasNormalMaps;", "uniform float terrainNormalMapStrength;", "uniform float terrainTextureSize;", "uniform float terrainHeightBlending;", @@ -28782,15 +28747,13 @@ "uniform vec2 terrainCliffCosines;", "uniform vec4 terrainBrush;", "uniform sampler2D terrainColorMap;", + "uniform sampler2D terrainNoiseMap;", "uniform vec3 terrainWetShore;", "varying vec2 vTerrainLocalXY;", "varying float vTerrainLocalZ;", "varying vec2 vTerrainWorldXY;", "varying float vTerrainUp;", "", - "float terrainHash(vec2 p) {", - " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", - "}", "// The rotation of the copies of textures used to make repetition less visible.", "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", @@ -28802,15 +28765,16 @@ " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", " return mix(bump, copyBump, patches);", "}", - "float terrainNoise(vec2 p) {", + "/**", + " * 4 independent value noises (one by channel), from 0 to 1, smoothly varying", + " * between random values at integer positions.", + " */", + "vec4 terrainNoise(vec2 p) {", " vec2 i = floor(p);", - " vec2 f = fract(p);", - " vec2 u = f * f * (3.0 - 2.0 * f);", - " return mix(", - " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", - " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", - " u.y", - " );", + " vec2 f = p - i;", + " // The read position is moved so that the linear interpolation of the", + " // texture between 2 random values becomes a smooth one.", + " return texture2D(terrainNoiseMap, (i + f * f * (3.0 - 2.0 * f) + 0.5) / ${NOISE_MAP_SIZE}.0);", "}", "`;", "// Holes are samples without any painted layer: the interpolated sum of the", @@ -28828,15 +28792,11 @@ "varying vec2 vTerrainLocalXY;", "`;", "", + "// Layers without texture, normal map, height blending or texture variation", + "// are compiled out (see TerrainRenderer.updateMaterial).", "const fragmentShaderCode = holeShaderCode + `", "// Borders between layers are made irregular and sharper, to look painted.", - "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", - "vec4 terrainJitter = vec4(", - " terrainNoise(terrainNoisePosition),", - " terrainNoise(terrainNoisePosition + 19.1),", - " terrainNoise(terrainNoisePosition + 37.7),", - " terrainNoise(terrainNoisePosition + 53.3)", - ");", + "vec4 terrainJitter = terrainNoise(vTerrainWorldXY / 24.0);", "// Layer weights are in a texture, so that painted details stay the same", "// whatever the level of detail of the ground.", "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", @@ -28847,48 +28807,61 @@ "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", "", "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", - "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", - "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", - "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", - "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "vec3 terrainTexture${layer} = texture2D(terrainLayerMap${layer}, terrainUv).rgb;", + "#else", + "vec3 terrainTexture${layer} = vec3(1.0);", + "#endif`", + ")}", "", "// Less visible repetition: in irregular patches, textures are replaced by a", "// rotated and shifted copy of themselves, and colors slowly vary.", "float terrainPatches = 0.0;", "vec2 terrainUv2 = terrainUv;", "float terrainColorVariation = 1.0;", - "if (terrainTextureVariation > 0.0) {", - " // Up to half of the ground is covered by the copies, each patch showing", - " // only one of them (mixing them would make them blurry).", - " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", - " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", - " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", - " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", - " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", - " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", - " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", - " terrainColorVariation += terrainTextureVariation * 0.3 *", - " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", - "}", + "#ifdef TERRAIN_TEXTURE_VARIATION", + "// Up to half of the ground is covered by the copies, each patch showing", + "// only one of them (mixing them would make them blurry).", + "float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + "terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3).x);", + "terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "terrainTexture${layer} = mix(terrainTexture${layer}, texture2D(terrainLayerMap${layer}, terrainUv2).rgb, terrainPatches);", + "#endif`", + ")}", + "terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11).y + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1).z - 0.75);", + "#endif", "", "// Height-based blending: the brightness of a texture, compared to its", "// average, is used as its height. Where layers meet, the high parts (stones,", "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", - "if (terrainHeightBlending > 0.0) {", - " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", - " vec4 terrainHeights = vec4(", - " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", - " );", - " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", - " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", - " // Only painted layers (and the cliff layer) can show.", - " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", - " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", - " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", - "}", + "#ifdef TERRAIN_HEIGHT_BLENDING", + "// Averages are computed once on the CPU, or read from the smallest mipmap", + "// when the image can't be read by the CPU.", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MIPMAP_AVERAGE_${layer}", + "vec3 terrainAverage${layer} = textureLod(terrainLayerMap${layer}, vec2(0.5), 16.0).rgb;", + "#else", + "vec3 terrainAverage${layer} = terrainLayerAverageColors[${layer}];", + "#endif`", + ")}", + "const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + "vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - terrainAverage0, terrainLuminance),", + " dot(terrainTexture1 - terrainAverage1, terrainLuminance),", + " dot(terrainTexture2 - terrainAverage2, terrainLuminance),", + " dot(terrainTexture3 - terrainAverage3, terrainLuminance)", + ");", + "vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + "float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + "// Only painted layers (and the cliff layer) can show.", + "vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + "terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + "terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "#endif", "", "vec3 terrainColor = terrainColorVariation * (", " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", @@ -28920,26 +28893,30 @@ "`;", "", "const fragmentShaderNormalCode = `", - "if (terrainHasNormalMaps > 0.5) {", - " vec3 terrainMapNormal =", - " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", - " terrainMapNormal.xy *= terrainNormalMapStrength;", - " // The X and Y of textures follow the X and Y of the 3D world, projected on", - " // the ground (the camera space of the normal is used).", - " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "#ifdef TERRAIN_NORMAL_MAPS", + "// Layers without normal map are flat.", + "vec3 terrainMapNormal = vec3(0.0);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_NORMAL_MAP_${layer}", + "terrainMapNormal += terrainWeights[${layer}] * terrainSampleNormal(terrainLayerNormalMap${layer}, terrainUv, terrainUv2, terrainPatches);", + "#else", + "terrainMapNormal.z += terrainWeights[${layer}];", + "#endif`", + ")}", + "terrainMapNormal.xy *= terrainNormalMapStrength;", + "// The X and Y of textures follow the X and Y of the 3D world, projected on", + "// the ground (the camera space of the normal is used).", + "vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "terrainTangent -= normal * dot(normal, terrainTangent);", + "// A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + "if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", " terrainTangent -= normal * dot(normal, terrainTangent);", - " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", - " if (dot(terrainTangent, terrainTangent) < 0.000001) {", - " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", - " terrainTangent -= normal * dot(normal, terrainTangent);", - " }", - " terrainTangent = normalize(terrainTangent);", - " vec3 terrainBitangent = cross(normal, terrainTangent);", - " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", "}", + "terrainTangent = normalize(terrainTangent);", + "vec3 terrainBitangent = cross(normal, terrainTangent);", + "normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "#endif", "`;", "", "let whiteTexture = null;", @@ -28960,7 +28937,30 @@ " return flatNormalTexture;", "};", "", + "let noiseTexture = null;", + "/** Random values, in 4 independent channels, read by `terrainNoise` in the shader. */", + "const getNoiseTexture = () => {", + " if (!noiseTexture) {", + " const random = createRandom(1);", + " const bytes = new Uint8Array(NOISE_MAP_SIZE * NOISE_MAP_SIZE * 4);", + " for (let index = 0; index < bytes.length; index++) {", + " bytes[index] = Math.floor(random() * 256);", + " }", + " noiseTexture = new THREE.DataTexture(bytes, NOISE_MAP_SIZE, NOISE_MAP_SIZE);", + " noiseTexture.wrapS = THREE.RepeatWrapping;", + " noiseTexture.wrapT = THREE.RepeatWrapping;", + " // No mipmaps: the shader moves the read position between samples.", + " noiseTexture.magFilter = THREE.LinearFilter;", + " noiseTexture.minFilter = THREE.LinearFilter;", + " noiseTexture.needsUpdate = true;", + " }", + " return noiseTexture;", + "};", + "", + "const DEFAULT_ANISOTROPY = 4;", + "/** @type {WeakMap>} */", "const layerTextures = new WeakMap();", + "/** @type {WeakMap>} */", "const layerNormalMaps = new WeakMap();", "/**", " * Textures of the image manager have no mipmaps: they would shimmer when", @@ -28968,12 +28968,18 @@ " * @param {gdjs.RuntimeGame} game", " * @param {string} resourceName", " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " * @param {number} anisotropy", " */", - "const getLayerTexture = (game, resourceName, isNormalMap) => {", + "const getLayerTexture = (game, resourceName, isNormalMap, anisotropy) => {", " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", - " const textures = isNormalMap ? layerNormalMaps : layerTextures;", - " let texture = textures.get(imageTexture);", + " const texturesByImage = isNormalMap ? layerNormalMaps : layerTextures;", + " let texturesByAnisotropy = texturesByImage.get(imageTexture);", + " if (!texturesByAnisotropy) {", + " texturesByAnisotropy = new Map();", + " texturesByImage.set(imageTexture, texturesByAnisotropy);", + " }", + " let texture = texturesByAnisotropy.get(anisotropy);", " if (!texture) {", " texture = imageTexture.clone();", " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", @@ -28981,13 +28987,71 @@ " texture.wrapT = THREE.RepeatWrapping;", " texture.minFilter = THREE.LinearMipmapLinearFilter;", " texture.generateMipmaps = true;", - " texture.anisotropy = 4;", + " texture.anisotropy = anisotropy;", " texture.needsUpdate = true;", - " textures.set(imageTexture, texture);", + " texturesByAnisotropy.set(anisotropy, texture);", " }", " return texture;", "};", "", + "/** @type {Float32Array | null} */", + "let srgbToLinearValues = null;", + "/** @type {WeakMap} */", + "const linearAverageColors = new WeakMap();", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Vector3 | null} The average color of the texture, in the", + " * linear color space (like colors read by shaders), or null if the image", + " * can't be read: not loaded yet, or from another domain without CORS.", + " */", + "const getLinearAverageColor = (texture) => {", + " const image = texture.image;", + " if (!image) return null;", + " const cachedColor = linearAverageColors.get(image);", + " if (cachedColor) return cachedColor;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return null;", + " const size = 64;", + " let pixels;", + " try {", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " // Downscaled with filtering, so that all pixels are counted.", + " context.imageSmoothingEnabled = true;", + " context.imageSmoothingQuality = 'high';", + " context.drawImage(image, 0, 0, size, size);", + " pixels = context.getImageData(0, 0, size, size).data;", + " } catch (error) {", + " return null;", + " }", + " if (!srgbToLinearValues) {", + " srgbToLinearValues = new Float32Array(256);", + " for (let value = 0; value < 256; value++) {", + " const srgb = value / 255;", + " srgbToLinearValues[value] = srgb <= 0.04045 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);", + " }", + " }", + " const isSrgb = texture.colorSpace === THREE.SRGBColorSpace;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += isSrgb ? srgbToLinearValues[pixels[index]] : pixels[index] / 255;", + " green += isSrgb ? srgbToLinearValues[pixels[index + 1]] : pixels[index + 1] / 255;", + " blue += isSrgb ? srgbToLinearValues[pixels[index + 2]] : pixels[index + 2] / 255;", + " }", + " const count = size * size;", + " const color = new THREE.Vector3(red / count, green / count, blue / count);", + " linearAverageColors.set(image, color);", + " return color;", + "};", + "", "/**", " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", " * weights, tint and wetness...), interpolated between samples.", @@ -29046,11 +29110,14 @@ " terrainLayerMap1: { value: getWhiteTexture() },", " terrainLayerMap2: { value: getWhiteTexture() },", " terrainLayerMap3: { value: getWhiteTexture() },", + " // Used by the height blending, in the linear color space.", + " terrainLayerAverageColors: {", + " value: [new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1)],", + " },", " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", - " terrainHasNormalMaps: { value: 0 },", " terrainNormalMapStrength: { value: 1 },", " terrainTextureSize: { value: 256 },", " terrainHeightBlending: { value: 0 },", @@ -29059,6 +29126,7 @@ " terrainCliffCosines: { value: new THREE.Vector2() },", " terrainBrush: { value: new THREE.Vector4() },", " terrainColorMap: { value: getWhiteTexture() },", + " terrainNoiseMap: { value: getNoiseTexture() },", " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", " terrainWetShore: { value: new THREE.Vector3() },", " // Scene units by 3D world unit.", @@ -29078,8 +29146,12 @@ " ['#include ', '#include \\n' + fragmentShaderNormalCode],", " ], 'Terrain3D');", " };", - " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", " this.hasHoles = false;", + " /** The defines of the features used by the terrain (see `updateMaterial`), without holes. */", + " this.featureDefines = [];", + " /** All the defines of the shader, separated by semicolons. */", + " this.shaderKey = '';", + " this.material.customProgramCacheKey = () => 'Terrain3D;' + this.shaderKey;", " // Without them, holes would cast shadows.", " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", @@ -29116,11 +29188,28 @@ " setHasHoles(hasHoles) {", " if (hasHoles === this.hasHoles) return;", " this.hasHoles = hasHoles;", + " this._updateShaderDefines();", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /**", + " * Compile the shader only with the features used by the terrain. It is", + " * compiled again only when they change: properties only change in the", + " * editor, holes can be made by actions.", + " */", + " _updateShaderDefines() {", + " const defines = this.hasHoles ? [...this.featureDefines, 'TERRAIN_HOLES'] : this.featureDefines;", + " const shaderKey = defines.join(';');", + " if (shaderKey === this.shaderKey) return;", " // The material has its own defines (STANDARD).", - " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", - " else delete this.material.defines.TERRAIN_HOLES;", + " for (const name of this.shaderKey ? this.shaderKey.split(';') : []) {", + " delete this.material.defines[name];", + " }", + " for (const name of defines) {", + " this.material.defines[name] = '';", + " }", + " this.shaderKey = shaderKey;", " this.material.needsUpdate = true;", - " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", " }", "", " /** @param {THREE.Mesh} mesh */", @@ -29352,16 +29441,38 @@ " object._getLayer3NormalMap(),", " object._getLayer4NormalMap(),", " ];", + " const anisotropy = Math.max(parseInt(object._getAnisotropy(), 10) || DEFAULT_ANISOTROPY, 1);", + " const heightBlending = clamp01(object._getHeightBlending());", + " const textureVariation = clamp01(object._getTextureVariation());", + " const featureDefines = [];", " for (let layer = 0; layer < LAYER_COUNT; layer++) {", " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", - " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", - " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " const layerTexture = getLayerTexture(game, textures[layer], false, anisotropy);", + " this.uniforms['terrainLayerMap' + layer].value = layerTexture;", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true, anisotropy);", + " const averageColor = this.uniforms.terrainLayerAverageColors.value[layer];", + " if (textures[layer]) {", + " featureDefines.push('TERRAIN_LAYER_MAP_' + layer);", + " const linearAverageColor = heightBlending > 0 ? getLinearAverageColor(layerTexture) : null;", + " if (linearAverageColor) {", + " averageColor.copy(linearAverageColor);", + " } else if (heightBlending > 0) {", + " featureDefines.push('TERRAIN_LAYER_MIPMAP_AVERAGE_' + layer);", + " }", + " } else {", + " averageColor.set(1, 1, 1);", + " }", + " if (normalMaps[layer]) featureDefines.push('TERRAIN_LAYER_NORMAL_MAP_' + layer);", " }", - " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " if (normalMaps.some((normalMap) => !!normalMap)) featureDefines.push('TERRAIN_NORMAL_MAPS');", + " if (heightBlending > 0) featureDefines.push('TERRAIN_HEIGHT_BLENDING');", + " if (textureVariation > 0) featureDefines.push('TERRAIN_TEXTURE_VARIATION');", + " this.featureDefines = featureDefines;", + " this._updateShaderDefines();", " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", - " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", - " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + " this.uniforms.terrainHeightBlending.value = heightBlending;", + " this.uniforms.terrainTextureVariation.value = textureVariation;", "", " const cliffLayer = parseInt(object._getCliffLayer(), 10);", " const cliffAngle = gdjs.toRad(object._getCliffAngle());", @@ -30279,40 +30390,21 @@ " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", "};", "", + "/** @type {WeakMap} */", "const averageColors = new WeakMap();", "let white = null;", "/**", " * @param {THREE.Texture} texture", - " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " * @returns {THREE.Color} The average color of the texture (white when it can't be read).", " */", "const getAverageColor = (texture) => {", - " const cachedColor = averageColors.get(texture);", - " if (cachedColor) return cachedColor;", - " const image = texture.image;", - " const isDrawable =", - " typeof document !== 'undefined' &&", - " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", - " image instanceof HTMLCanvasElement ||", - " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", - " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", - " const size = 8;", - " const canvas = document.createElement('canvas');", - " canvas.width = size;", - " canvas.height = size;", - " const context = canvas.getContext('2d');", - " context.drawImage(image, 0, 0, size, size);", - " const pixels = context.getImageData(0, 0, size, size).data;", - " let red = 0;", - " let green = 0;", - " let blue = 0;", - " for (let index = 0; index < pixels.length; index += 4) {", - " red += pixels[index];", - " green += pixels[index + 1];", - " blue += pixels[index + 2];", + " const linearAverageColor = getLinearAverageColor(texture);", + " if (!linearAverageColor) return white || (white = new THREE.Color(1, 1, 1));", + " let color = averageColors.get(linearAverageColor);", + " if (!color) {", + " color = new THREE.Color(linearAverageColor.x, linearAverageColor.y, linearAverageColor.z);", + " averageColors.set(linearAverageColor, color);", " }", - " const count = size * size * 255;", - " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", - " averageColors.set(texture, color);", " return color;", "};", "", @@ -33926,6 +34018,37 @@ "group": "Rendering", "name": "ReceiveShadow" }, + { + "value": "4", + "type": "Choice", + "label": "Anisotropic filtering", + "description": "Keeps layer textures sharp where the ground is seen at a low angle (like from a car). Lower is faster on slow graphics cards, but blurs the ground in the distance.", + "group": "Rendering", + "choices": [ + { + "label": "None (fastest)", + "value": "1" + }, + { + "label": "2x", + "value": "2" + }, + { + "label": "4x", + "value": "4" + }, + { + "label": "8x", + "value": "8" + }, + { + "label": "16x (sharpest)", + "value": "16" + } + ], + "advanced": true, + "name": "Anisotropy" + }, { "value": "", "type": "String", @@ -34039,6 +34162,9 @@ }, { "propertyName": "ReceiveShadow" + }, + { + "propertyName": "Anisotropy" } ] }, diff --git a/examples/starting-3D-platformer/theme-slots.json b/examples/starting-3D-platformer/theme-slots.json index 1b6aeb8d6..a0ae2cbf5 100644 --- a/examples/starting-3D-platformer/theme-slots.json +++ b/examples/starting-3D-platformer/theme-slots.json @@ -1,12 +1,11 @@ { "version": 1, "objects": { - "scene:Game Scene/Ground": { - "front": "env.ground", - "left": "env.wall", - "right": "env.wall", - "top": "env.wall", - "bottom": "env.wall" + "scene:Game Scene/Terrain": { + "Layer1Texture": { + "slot": "terrain.ground", + "normalMap": "Layer1NormalMap" + } }, "scene:Game Scene/Player": "character.player", "scene:Game Scene/Obstacle": { @@ -27,5 +26,10 @@ }, "effects": { "effect:Game Scene//SkyBox": "sky.day" - } + }, + "ignoredObjects": [ + "object:Terrain3D::Terrain3D/AreaPlaceholder", + "object:Terrain3D::TerrainGrass/AreaPlaceholder", + "object:Terrain3D::ScatteredModels/AreaPlaceholder" + ] } diff --git a/examples/starting-3d-car-racing/starting-3d-car-racing.json b/examples/starting-3d-car-racing/starting-3d-car-racing.json index 57e15dc05..066540e30 100644 --- a/examples/starting-3d-car-racing/starting-3d-car-racing.json +++ b/examples/starting-3d-car-racing/starting-3d-car-racing.json @@ -13158,7 +13158,7 @@ "name": "Terrain3D", "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", - "version": "0.1.0", + "version": "0.2.0", "description": [ "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", "", @@ -14258,8 +14258,17 @@ "vTerrainLocalXY = position.xy;", "vTerrainLocalZ = position.z;", "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", - "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "// The world normal, from the camera space normal (computed by Three.js with a", + "// matrix inverted on the CPU), instead of inverting a matrix for each vertex.", + "vTerrainUp = inverseTransformDirection(transformedNormal, viewMatrix).z;", "`;", + "/** @param {(layer: number) => string} getLayerCode */", + "const forEachLayerCode = (getLayerCode) => [0, 1, 2, 3].map(getLayerCode).join('\\n');", + "", + "// Noise is read from a texture of random values, repeated every", + "// NOISE_MAP_SIZE units of noise: 1 texture read instead of 16 hashes.", + "const NOISE_MAP_SIZE = 256;", + "", "const fragmentShaderDeclarations = `", "uniform sampler2D terrainSplatMap;", "uniform vec2 terrainSplatUvScaleAndOffset;", @@ -14268,11 +14277,11 @@ "uniform sampler2D terrainLayerMap1;", "uniform sampler2D terrainLayerMap2;", "uniform sampler2D terrainLayerMap3;", + "uniform vec3 terrainLayerAverageColors[4];", "uniform sampler2D terrainLayerNormalMap0;", "uniform sampler2D terrainLayerNormalMap1;", "uniform sampler2D terrainLayerNormalMap2;", "uniform sampler2D terrainLayerNormalMap3;", - "uniform float terrainHasNormalMaps;", "uniform float terrainNormalMapStrength;", "uniform float terrainTextureSize;", "uniform float terrainHeightBlending;", @@ -14281,15 +14290,13 @@ "uniform vec2 terrainCliffCosines;", "uniform vec4 terrainBrush;", "uniform sampler2D terrainColorMap;", + "uniform sampler2D terrainNoiseMap;", "uniform vec3 terrainWetShore;", "varying vec2 vTerrainLocalXY;", "varying float vTerrainLocalZ;", "varying vec2 vTerrainWorldXY;", "varying float vTerrainUp;", "", - "float terrainHash(vec2 p) {", - " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", - "}", "// The rotation of the copies of textures used to make repetition less visible.", "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", @@ -14301,15 +14308,16 @@ " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", " return mix(bump, copyBump, patches);", "}", - "float terrainNoise(vec2 p) {", + "/**", + " * 4 independent value noises (one by channel), from 0 to 1, smoothly varying", + " * between random values at integer positions.", + " */", + "vec4 terrainNoise(vec2 p) {", " vec2 i = floor(p);", - " vec2 f = fract(p);", - " vec2 u = f * f * (3.0 - 2.0 * f);", - " return mix(", - " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", - " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", - " u.y", - " );", + " vec2 f = p - i;", + " // The read position is moved so that the linear interpolation of the", + " // texture between 2 random values becomes a smooth one.", + " return texture2D(terrainNoiseMap, (i + f * f * (3.0 - 2.0 * f) + 0.5) / ${NOISE_MAP_SIZE}.0);", "}", "`;", "// Holes are samples without any painted layer: the interpolated sum of the", @@ -14327,15 +14335,11 @@ "varying vec2 vTerrainLocalXY;", "`;", "", + "// Layers without texture, normal map, height blending or texture variation", + "// are compiled out (see TerrainRenderer.updateMaterial).", "const fragmentShaderCode = holeShaderCode + `", "// Borders between layers are made irregular and sharper, to look painted.", - "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", - "vec4 terrainJitter = vec4(", - " terrainNoise(terrainNoisePosition),", - " terrainNoise(terrainNoisePosition + 19.1),", - " terrainNoise(terrainNoisePosition + 37.7),", - " terrainNoise(terrainNoisePosition + 53.3)", - ");", + "vec4 terrainJitter = terrainNoise(vTerrainWorldXY / 24.0);", "// Layer weights are in a texture, so that painted details stay the same", "// whatever the level of detail of the ground.", "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", @@ -14346,48 +14350,61 @@ "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", "", "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", - "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", - "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", - "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", - "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "vec3 terrainTexture${layer} = texture2D(terrainLayerMap${layer}, terrainUv).rgb;", + "#else", + "vec3 terrainTexture${layer} = vec3(1.0);", + "#endif`", + ")}", "", "// Less visible repetition: in irregular patches, textures are replaced by a", "// rotated and shifted copy of themselves, and colors slowly vary.", "float terrainPatches = 0.0;", "vec2 terrainUv2 = terrainUv;", "float terrainColorVariation = 1.0;", - "if (terrainTextureVariation > 0.0) {", - " // Up to half of the ground is covered by the copies, each patch showing", - " // only one of them (mixing them would make them blurry).", - " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", - " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", - " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", - " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", - " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", - " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", - " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", - " terrainColorVariation += terrainTextureVariation * 0.3 *", - " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", - "}", + "#ifdef TERRAIN_TEXTURE_VARIATION", + "// Up to half of the ground is covered by the copies, each patch showing", + "// only one of them (mixing them would make them blurry).", + "float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + "terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3).x);", + "terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "terrainTexture${layer} = mix(terrainTexture${layer}, texture2D(terrainLayerMap${layer}, terrainUv2).rgb, terrainPatches);", + "#endif`", + ")}", + "terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11).y + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1).z - 0.75);", + "#endif", "", "// Height-based blending: the brightness of a texture, compared to its", "// average, is used as its height. Where layers meet, the high parts (stones,", "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", - "if (terrainHeightBlending > 0.0) {", - " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", - " vec4 terrainHeights = vec4(", - " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", - " );", - " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", - " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", - " // Only painted layers (and the cliff layer) can show.", - " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", - " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", - " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", - "}", + "#ifdef TERRAIN_HEIGHT_BLENDING", + "// Averages are computed once on the CPU, or read from the smallest mipmap", + "// when the image can't be read by the CPU.", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MIPMAP_AVERAGE_${layer}", + "vec3 terrainAverage${layer} = textureLod(terrainLayerMap${layer}, vec2(0.5), 16.0).rgb;", + "#else", + "vec3 terrainAverage${layer} = terrainLayerAverageColors[${layer}];", + "#endif`", + ")}", + "const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + "vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - terrainAverage0, terrainLuminance),", + " dot(terrainTexture1 - terrainAverage1, terrainLuminance),", + " dot(terrainTexture2 - terrainAverage2, terrainLuminance),", + " dot(terrainTexture3 - terrainAverage3, terrainLuminance)", + ");", + "vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + "float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + "// Only painted layers (and the cliff layer) can show.", + "vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + "terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + "terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "#endif", "", "vec3 terrainColor = terrainColorVariation * (", " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", @@ -14419,26 +14436,30 @@ "`;", "", "const fragmentShaderNormalCode = `", - "if (terrainHasNormalMaps > 0.5) {", - " vec3 terrainMapNormal =", - " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", - " terrainMapNormal.xy *= terrainNormalMapStrength;", - " // The X and Y of textures follow the X and Y of the 3D world, projected on", - " // the ground (the camera space of the normal is used).", - " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "#ifdef TERRAIN_NORMAL_MAPS", + "// Layers without normal map are flat.", + "vec3 terrainMapNormal = vec3(0.0);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_NORMAL_MAP_${layer}", + "terrainMapNormal += terrainWeights[${layer}] * terrainSampleNormal(terrainLayerNormalMap${layer}, terrainUv, terrainUv2, terrainPatches);", + "#else", + "terrainMapNormal.z += terrainWeights[${layer}];", + "#endif`", + ")}", + "terrainMapNormal.xy *= terrainNormalMapStrength;", + "// The X and Y of textures follow the X and Y of the 3D world, projected on", + "// the ground (the camera space of the normal is used).", + "vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "terrainTangent -= normal * dot(normal, terrainTangent);", + "// A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + "if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", " terrainTangent -= normal * dot(normal, terrainTangent);", - " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", - " if (dot(terrainTangent, terrainTangent) < 0.000001) {", - " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", - " terrainTangent -= normal * dot(normal, terrainTangent);", - " }", - " terrainTangent = normalize(terrainTangent);", - " vec3 terrainBitangent = cross(normal, terrainTangent);", - " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", "}", + "terrainTangent = normalize(terrainTangent);", + "vec3 terrainBitangent = cross(normal, terrainTangent);", + "normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "#endif", "`;", "", "let whiteTexture = null;", @@ -14459,7 +14480,30 @@ " return flatNormalTexture;", "};", "", + "let noiseTexture = null;", + "/** Random values, in 4 independent channels, read by `terrainNoise` in the shader. */", + "const getNoiseTexture = () => {", + " if (!noiseTexture) {", + " const random = createRandom(1);", + " const bytes = new Uint8Array(NOISE_MAP_SIZE * NOISE_MAP_SIZE * 4);", + " for (let index = 0; index < bytes.length; index++) {", + " bytes[index] = Math.floor(random() * 256);", + " }", + " noiseTexture = new THREE.DataTexture(bytes, NOISE_MAP_SIZE, NOISE_MAP_SIZE);", + " noiseTexture.wrapS = THREE.RepeatWrapping;", + " noiseTexture.wrapT = THREE.RepeatWrapping;", + " // No mipmaps: the shader moves the read position between samples.", + " noiseTexture.magFilter = THREE.LinearFilter;", + " noiseTexture.minFilter = THREE.LinearFilter;", + " noiseTexture.needsUpdate = true;", + " }", + " return noiseTexture;", + "};", + "", + "const DEFAULT_ANISOTROPY = 4;", + "/** @type {WeakMap>} */", "const layerTextures = new WeakMap();", + "/** @type {WeakMap>} */", "const layerNormalMaps = new WeakMap();", "/**", " * Textures of the image manager have no mipmaps: they would shimmer when", @@ -14467,12 +14511,18 @@ " * @param {gdjs.RuntimeGame} game", " * @param {string} resourceName", " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " * @param {number} anisotropy", " */", - "const getLayerTexture = (game, resourceName, isNormalMap) => {", + "const getLayerTexture = (game, resourceName, isNormalMap, anisotropy) => {", " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", - " const textures = isNormalMap ? layerNormalMaps : layerTextures;", - " let texture = textures.get(imageTexture);", + " const texturesByImage = isNormalMap ? layerNormalMaps : layerTextures;", + " let texturesByAnisotropy = texturesByImage.get(imageTexture);", + " if (!texturesByAnisotropy) {", + " texturesByAnisotropy = new Map();", + " texturesByImage.set(imageTexture, texturesByAnisotropy);", + " }", + " let texture = texturesByAnisotropy.get(anisotropy);", " if (!texture) {", " texture = imageTexture.clone();", " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", @@ -14480,13 +14530,71 @@ " texture.wrapT = THREE.RepeatWrapping;", " texture.minFilter = THREE.LinearMipmapLinearFilter;", " texture.generateMipmaps = true;", - " texture.anisotropy = 4;", + " texture.anisotropy = anisotropy;", " texture.needsUpdate = true;", - " textures.set(imageTexture, texture);", + " texturesByAnisotropy.set(anisotropy, texture);", " }", " return texture;", "};", "", + "/** @type {Float32Array | null} */", + "let srgbToLinearValues = null;", + "/** @type {WeakMap} */", + "const linearAverageColors = new WeakMap();", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Vector3 | null} The average color of the texture, in the", + " * linear color space (like colors read by shaders), or null if the image", + " * can't be read: not loaded yet, or from another domain without CORS.", + " */", + "const getLinearAverageColor = (texture) => {", + " const image = texture.image;", + " if (!image) return null;", + " const cachedColor = linearAverageColors.get(image);", + " if (cachedColor) return cachedColor;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return null;", + " const size = 64;", + " let pixels;", + " try {", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " // Downscaled with filtering, so that all pixels are counted.", + " context.imageSmoothingEnabled = true;", + " context.imageSmoothingQuality = 'high';", + " context.drawImage(image, 0, 0, size, size);", + " pixels = context.getImageData(0, 0, size, size).data;", + " } catch (error) {", + " return null;", + " }", + " if (!srgbToLinearValues) {", + " srgbToLinearValues = new Float32Array(256);", + " for (let value = 0; value < 256; value++) {", + " const srgb = value / 255;", + " srgbToLinearValues[value] = srgb <= 0.04045 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);", + " }", + " }", + " const isSrgb = texture.colorSpace === THREE.SRGBColorSpace;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += isSrgb ? srgbToLinearValues[pixels[index]] : pixels[index] / 255;", + " green += isSrgb ? srgbToLinearValues[pixels[index + 1]] : pixels[index + 1] / 255;", + " blue += isSrgb ? srgbToLinearValues[pixels[index + 2]] : pixels[index + 2] / 255;", + " }", + " const count = size * size;", + " const color = new THREE.Vector3(red / count, green / count, blue / count);", + " linearAverageColors.set(image, color);", + " return color;", + "};", + "", "/**", " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", " * weights, tint and wetness...), interpolated between samples.", @@ -14545,11 +14653,14 @@ " terrainLayerMap1: { value: getWhiteTexture() },", " terrainLayerMap2: { value: getWhiteTexture() },", " terrainLayerMap3: { value: getWhiteTexture() },", + " // Used by the height blending, in the linear color space.", + " terrainLayerAverageColors: {", + " value: [new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1)],", + " },", " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", - " terrainHasNormalMaps: { value: 0 },", " terrainNormalMapStrength: { value: 1 },", " terrainTextureSize: { value: 256 },", " terrainHeightBlending: { value: 0 },", @@ -14558,6 +14669,7 @@ " terrainCliffCosines: { value: new THREE.Vector2() },", " terrainBrush: { value: new THREE.Vector4() },", " terrainColorMap: { value: getWhiteTexture() },", + " terrainNoiseMap: { value: getNoiseTexture() },", " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", " terrainWetShore: { value: new THREE.Vector3() },", " // Scene units by 3D world unit.", @@ -14577,8 +14689,12 @@ " ['#include ', '#include \\n' + fragmentShaderNormalCode],", " ], 'Terrain3D');", " };", - " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", " this.hasHoles = false;", + " /** The defines of the features used by the terrain (see `updateMaterial`), without holes. */", + " this.featureDefines = [];", + " /** All the defines of the shader, separated by semicolons. */", + " this.shaderKey = '';", + " this.material.customProgramCacheKey = () => 'Terrain3D;' + this.shaderKey;", " // Without them, holes would cast shadows.", " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", @@ -14615,11 +14731,28 @@ " setHasHoles(hasHoles) {", " if (hasHoles === this.hasHoles) return;", " this.hasHoles = hasHoles;", + " this._updateShaderDefines();", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /**", + " * Compile the shader only with the features used by the terrain. It is", + " * compiled again only when they change: properties only change in the", + " * editor, holes can be made by actions.", + " */", + " _updateShaderDefines() {", + " const defines = this.hasHoles ? [...this.featureDefines, 'TERRAIN_HOLES'] : this.featureDefines;", + " const shaderKey = defines.join(';');", + " if (shaderKey === this.shaderKey) return;", " // The material has its own defines (STANDARD).", - " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", - " else delete this.material.defines.TERRAIN_HOLES;", + " for (const name of this.shaderKey ? this.shaderKey.split(';') : []) {", + " delete this.material.defines[name];", + " }", + " for (const name of defines) {", + " this.material.defines[name] = '';", + " }", + " this.shaderKey = shaderKey;", " this.material.needsUpdate = true;", - " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", " }", "", " /** @param {THREE.Mesh} mesh */", @@ -14851,16 +14984,38 @@ " object._getLayer3NormalMap(),", " object._getLayer4NormalMap(),", " ];", + " const anisotropy = Math.max(parseInt(object._getAnisotropy(), 10) || DEFAULT_ANISOTROPY, 1);", + " const heightBlending = clamp01(object._getHeightBlending());", + " const textureVariation = clamp01(object._getTextureVariation());", + " const featureDefines = [];", " for (let layer = 0; layer < LAYER_COUNT; layer++) {", " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", - " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", - " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " const layerTexture = getLayerTexture(game, textures[layer], false, anisotropy);", + " this.uniforms['terrainLayerMap' + layer].value = layerTexture;", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true, anisotropy);", + " const averageColor = this.uniforms.terrainLayerAverageColors.value[layer];", + " if (textures[layer]) {", + " featureDefines.push('TERRAIN_LAYER_MAP_' + layer);", + " const linearAverageColor = heightBlending > 0 ? getLinearAverageColor(layerTexture) : null;", + " if (linearAverageColor) {", + " averageColor.copy(linearAverageColor);", + " } else if (heightBlending > 0) {", + " featureDefines.push('TERRAIN_LAYER_MIPMAP_AVERAGE_' + layer);", + " }", + " } else {", + " averageColor.set(1, 1, 1);", + " }", + " if (normalMaps[layer]) featureDefines.push('TERRAIN_LAYER_NORMAL_MAP_' + layer);", " }", - " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " if (normalMaps.some((normalMap) => !!normalMap)) featureDefines.push('TERRAIN_NORMAL_MAPS');", + " if (heightBlending > 0) featureDefines.push('TERRAIN_HEIGHT_BLENDING');", + " if (textureVariation > 0) featureDefines.push('TERRAIN_TEXTURE_VARIATION');", + " this.featureDefines = featureDefines;", + " this._updateShaderDefines();", " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", - " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", - " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + " this.uniforms.terrainHeightBlending.value = heightBlending;", + " this.uniforms.terrainTextureVariation.value = textureVariation;", "", " const cliffLayer = parseInt(object._getCliffLayer(), 10);", " const cliffAngle = gdjs.toRad(object._getCliffAngle());", @@ -15778,40 +15933,21 @@ " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", "};", "", + "/** @type {WeakMap} */", "const averageColors = new WeakMap();", "let white = null;", "/**", " * @param {THREE.Texture} texture", - " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " * @returns {THREE.Color} The average color of the texture (white when it can't be read).", " */", "const getAverageColor = (texture) => {", - " const cachedColor = averageColors.get(texture);", - " if (cachedColor) return cachedColor;", - " const image = texture.image;", - " const isDrawable =", - " typeof document !== 'undefined' &&", - " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", - " image instanceof HTMLCanvasElement ||", - " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", - " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", - " const size = 8;", - " const canvas = document.createElement('canvas');", - " canvas.width = size;", - " canvas.height = size;", - " const context = canvas.getContext('2d');", - " context.drawImage(image, 0, 0, size, size);", - " const pixels = context.getImageData(0, 0, size, size).data;", - " let red = 0;", - " let green = 0;", - " let blue = 0;", - " for (let index = 0; index < pixels.length; index += 4) {", - " red += pixels[index];", - " green += pixels[index + 1];", - " blue += pixels[index + 2];", + " const linearAverageColor = getLinearAverageColor(texture);", + " if (!linearAverageColor) return white || (white = new THREE.Color(1, 1, 1));", + " let color = averageColors.get(linearAverageColor);", + " if (!color) {", + " color = new THREE.Color(linearAverageColor.x, linearAverageColor.y, linearAverageColor.z);", + " averageColors.set(linearAverageColor, color);", " }", - " const count = size * size * 255;", - " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", - " averageColors.set(texture, color);", " return color;", "};", "", @@ -19425,6 +19561,37 @@ "group": "Rendering", "name": "ReceiveShadow" }, + { + "value": "4", + "type": "Choice", + "label": "Anisotropic filtering", + "description": "Keeps layer textures sharp where the ground is seen at a low angle (like from a car). Lower is faster on slow graphics cards, but blurs the ground in the distance.", + "group": "Rendering", + "choices": [ + { + "label": "None (fastest)", + "value": "1" + }, + { + "label": "2x", + "value": "2" + }, + { + "label": "4x", + "value": "4" + }, + { + "label": "8x", + "value": "8" + }, + { + "label": "16x (sharpest)", + "value": "16" + } + ], + "advanced": true, + "name": "Anisotropy" + }, { "value": "", "type": "String", @@ -19538,6 +19705,9 @@ }, { "propertyName": "ReceiveShadow" + }, + { + "propertyName": "Anisotropy" } ] }, diff --git a/examples/starting-3d-car-racing/theme-slots.json b/examples/starting-3d-car-racing/theme-slots.json index 83259ff28..962498f93 100644 --- a/examples/starting-3d-car-racing/theme-slots.json +++ b/examples/starting-3d-car-racing/theme-slots.json @@ -2,7 +2,12 @@ "version": 1, "objects": { "scene:Game Scene/Road_3D": "env.road", - "scene:Game Scene/Grass_3D": "env.ground", + "scene:Game Scene/Terrain": { + "Layer1Texture": { + "slot": "terrain.ground", + "normalMap": "Layer1NormalMap" + } + }, "scene:Game Scene/PlayerCar": "vehicle.car", "scene:Game Scene/TrafficCone": "prop.obstacle", "scene:Game Scene/FinishLine_3D": { @@ -16,5 +21,10 @@ }, "effects": { "effect:Game Scene//SkyBox": "sky.day" - } + }, + "ignoredObjects": [ + "object:Terrain3D::Terrain3D/AreaPlaceholder", + "object:Terrain3D::TerrainGrass/AreaPlaceholder", + "object:Terrain3D::ScatteredModels/AreaPlaceholder" + ] } diff --git a/examples/starting-3d-driving/starting-3d-driving.json b/examples/starting-3d-driving/starting-3d-driving.json index 8d2b0d827..ae2301a7b 100644 --- a/examples/starting-3d-driving/starting-3d-driving.json +++ b/examples/starting-3d-driving/starting-3d-driving.json @@ -12651,7 +12651,7 @@ "name": "Terrain3D", "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", - "version": "0.1.0", + "version": "0.2.0", "description": [ "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", "", @@ -13751,8 +13751,17 @@ "vTerrainLocalXY = position.xy;", "vTerrainLocalZ = position.z;", "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", - "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "// The world normal, from the camera space normal (computed by Three.js with a", + "// matrix inverted on the CPU), instead of inverting a matrix for each vertex.", + "vTerrainUp = inverseTransformDirection(transformedNormal, viewMatrix).z;", "`;", + "/** @param {(layer: number) => string} getLayerCode */", + "const forEachLayerCode = (getLayerCode) => [0, 1, 2, 3].map(getLayerCode).join('\\n');", + "", + "// Noise is read from a texture of random values, repeated every", + "// NOISE_MAP_SIZE units of noise: 1 texture read instead of 16 hashes.", + "const NOISE_MAP_SIZE = 256;", + "", "const fragmentShaderDeclarations = `", "uniform sampler2D terrainSplatMap;", "uniform vec2 terrainSplatUvScaleAndOffset;", @@ -13761,11 +13770,11 @@ "uniform sampler2D terrainLayerMap1;", "uniform sampler2D terrainLayerMap2;", "uniform sampler2D terrainLayerMap3;", + "uniform vec3 terrainLayerAverageColors[4];", "uniform sampler2D terrainLayerNormalMap0;", "uniform sampler2D terrainLayerNormalMap1;", "uniform sampler2D terrainLayerNormalMap2;", "uniform sampler2D terrainLayerNormalMap3;", - "uniform float terrainHasNormalMaps;", "uniform float terrainNormalMapStrength;", "uniform float terrainTextureSize;", "uniform float terrainHeightBlending;", @@ -13774,15 +13783,13 @@ "uniform vec2 terrainCliffCosines;", "uniform vec4 terrainBrush;", "uniform sampler2D terrainColorMap;", + "uniform sampler2D terrainNoiseMap;", "uniform vec3 terrainWetShore;", "varying vec2 vTerrainLocalXY;", "varying float vTerrainLocalZ;", "varying vec2 vTerrainWorldXY;", "varying float vTerrainUp;", "", - "float terrainHash(vec2 p) {", - " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", - "}", "// The rotation of the copies of textures used to make repetition less visible.", "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", @@ -13794,15 +13801,16 @@ " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", " return mix(bump, copyBump, patches);", "}", - "float terrainNoise(vec2 p) {", + "/**", + " * 4 independent value noises (one by channel), from 0 to 1, smoothly varying", + " * between random values at integer positions.", + " */", + "vec4 terrainNoise(vec2 p) {", " vec2 i = floor(p);", - " vec2 f = fract(p);", - " vec2 u = f * f * (3.0 - 2.0 * f);", - " return mix(", - " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", - " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", - " u.y", - " );", + " vec2 f = p - i;", + " // The read position is moved so that the linear interpolation of the", + " // texture between 2 random values becomes a smooth one.", + " return texture2D(terrainNoiseMap, (i + f * f * (3.0 - 2.0 * f) + 0.5) / ${NOISE_MAP_SIZE}.0);", "}", "`;", "// Holes are samples without any painted layer: the interpolated sum of the", @@ -13820,15 +13828,11 @@ "varying vec2 vTerrainLocalXY;", "`;", "", + "// Layers without texture, normal map, height blending or texture variation", + "// are compiled out (see TerrainRenderer.updateMaterial).", "const fragmentShaderCode = holeShaderCode + `", "// Borders between layers are made irregular and sharper, to look painted.", - "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", - "vec4 terrainJitter = vec4(", - " terrainNoise(terrainNoisePosition),", - " terrainNoise(terrainNoisePosition + 19.1),", - " terrainNoise(terrainNoisePosition + 37.7),", - " terrainNoise(terrainNoisePosition + 53.3)", - ");", + "vec4 terrainJitter = terrainNoise(vTerrainWorldXY / 24.0);", "// Layer weights are in a texture, so that painted details stay the same", "// whatever the level of detail of the ground.", "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", @@ -13839,48 +13843,61 @@ "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", "", "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", - "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", - "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", - "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", - "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "vec3 terrainTexture${layer} = texture2D(terrainLayerMap${layer}, terrainUv).rgb;", + "#else", + "vec3 terrainTexture${layer} = vec3(1.0);", + "#endif`", + ")}", "", "// Less visible repetition: in irregular patches, textures are replaced by a", "// rotated and shifted copy of themselves, and colors slowly vary.", "float terrainPatches = 0.0;", "vec2 terrainUv2 = terrainUv;", "float terrainColorVariation = 1.0;", - "if (terrainTextureVariation > 0.0) {", - " // Up to half of the ground is covered by the copies, each patch showing", - " // only one of them (mixing them would make them blurry).", - " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", - " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", - " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", - " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", - " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", - " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", - " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", - " terrainColorVariation += terrainTextureVariation * 0.3 *", - " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", - "}", + "#ifdef TERRAIN_TEXTURE_VARIATION", + "// Up to half of the ground is covered by the copies, each patch showing", + "// only one of them (mixing them would make them blurry).", + "float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + "terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3).x);", + "terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "terrainTexture${layer} = mix(terrainTexture${layer}, texture2D(terrainLayerMap${layer}, terrainUv2).rgb, terrainPatches);", + "#endif`", + ")}", + "terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11).y + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1).z - 0.75);", + "#endif", "", "// Height-based blending: the brightness of a texture, compared to its", "// average, is used as its height. Where layers meet, the high parts (stones,", "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", - "if (terrainHeightBlending > 0.0) {", - " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", - " vec4 terrainHeights = vec4(", - " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", - " );", - " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", - " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", - " // Only painted layers (and the cliff layer) can show.", - " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", - " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", - " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", - "}", + "#ifdef TERRAIN_HEIGHT_BLENDING", + "// Averages are computed once on the CPU, or read from the smallest mipmap", + "// when the image can't be read by the CPU.", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MIPMAP_AVERAGE_${layer}", + "vec3 terrainAverage${layer} = textureLod(terrainLayerMap${layer}, vec2(0.5), 16.0).rgb;", + "#else", + "vec3 terrainAverage${layer} = terrainLayerAverageColors[${layer}];", + "#endif`", + ")}", + "const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + "vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - terrainAverage0, terrainLuminance),", + " dot(terrainTexture1 - terrainAverage1, terrainLuminance),", + " dot(terrainTexture2 - terrainAverage2, terrainLuminance),", + " dot(terrainTexture3 - terrainAverage3, terrainLuminance)", + ");", + "vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + "float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + "// Only painted layers (and the cliff layer) can show.", + "vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + "terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + "terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "#endif", "", "vec3 terrainColor = terrainColorVariation * (", " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", @@ -13912,26 +13929,30 @@ "`;", "", "const fragmentShaderNormalCode = `", - "if (terrainHasNormalMaps > 0.5) {", - " vec3 terrainMapNormal =", - " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", - " terrainMapNormal.xy *= terrainNormalMapStrength;", - " // The X and Y of textures follow the X and Y of the 3D world, projected on", - " // the ground (the camera space of the normal is used).", - " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "#ifdef TERRAIN_NORMAL_MAPS", + "// Layers without normal map are flat.", + "vec3 terrainMapNormal = vec3(0.0);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_NORMAL_MAP_${layer}", + "terrainMapNormal += terrainWeights[${layer}] * terrainSampleNormal(terrainLayerNormalMap${layer}, terrainUv, terrainUv2, terrainPatches);", + "#else", + "terrainMapNormal.z += terrainWeights[${layer}];", + "#endif`", + ")}", + "terrainMapNormal.xy *= terrainNormalMapStrength;", + "// The X and Y of textures follow the X and Y of the 3D world, projected on", + "// the ground (the camera space of the normal is used).", + "vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "terrainTangent -= normal * dot(normal, terrainTangent);", + "// A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + "if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", " terrainTangent -= normal * dot(normal, terrainTangent);", - " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", - " if (dot(terrainTangent, terrainTangent) < 0.000001) {", - " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", - " terrainTangent -= normal * dot(normal, terrainTangent);", - " }", - " terrainTangent = normalize(terrainTangent);", - " vec3 terrainBitangent = cross(normal, terrainTangent);", - " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", "}", + "terrainTangent = normalize(terrainTangent);", + "vec3 terrainBitangent = cross(normal, terrainTangent);", + "normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "#endif", "`;", "", "let whiteTexture = null;", @@ -13952,7 +13973,30 @@ " return flatNormalTexture;", "};", "", + "let noiseTexture = null;", + "/** Random values, in 4 independent channels, read by `terrainNoise` in the shader. */", + "const getNoiseTexture = () => {", + " if (!noiseTexture) {", + " const random = createRandom(1);", + " const bytes = new Uint8Array(NOISE_MAP_SIZE * NOISE_MAP_SIZE * 4);", + " for (let index = 0; index < bytes.length; index++) {", + " bytes[index] = Math.floor(random() * 256);", + " }", + " noiseTexture = new THREE.DataTexture(bytes, NOISE_MAP_SIZE, NOISE_MAP_SIZE);", + " noiseTexture.wrapS = THREE.RepeatWrapping;", + " noiseTexture.wrapT = THREE.RepeatWrapping;", + " // No mipmaps: the shader moves the read position between samples.", + " noiseTexture.magFilter = THREE.LinearFilter;", + " noiseTexture.minFilter = THREE.LinearFilter;", + " noiseTexture.needsUpdate = true;", + " }", + " return noiseTexture;", + "};", + "", + "const DEFAULT_ANISOTROPY = 4;", + "/** @type {WeakMap>} */", "const layerTextures = new WeakMap();", + "/** @type {WeakMap>} */", "const layerNormalMaps = new WeakMap();", "/**", " * Textures of the image manager have no mipmaps: they would shimmer when", @@ -13960,12 +14004,18 @@ " * @param {gdjs.RuntimeGame} game", " * @param {string} resourceName", " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " * @param {number} anisotropy", " */", - "const getLayerTexture = (game, resourceName, isNormalMap) => {", + "const getLayerTexture = (game, resourceName, isNormalMap, anisotropy) => {", " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", - " const textures = isNormalMap ? layerNormalMaps : layerTextures;", - " let texture = textures.get(imageTexture);", + " const texturesByImage = isNormalMap ? layerNormalMaps : layerTextures;", + " let texturesByAnisotropy = texturesByImage.get(imageTexture);", + " if (!texturesByAnisotropy) {", + " texturesByAnisotropy = new Map();", + " texturesByImage.set(imageTexture, texturesByAnisotropy);", + " }", + " let texture = texturesByAnisotropy.get(anisotropy);", " if (!texture) {", " texture = imageTexture.clone();", " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", @@ -13973,13 +14023,71 @@ " texture.wrapT = THREE.RepeatWrapping;", " texture.minFilter = THREE.LinearMipmapLinearFilter;", " texture.generateMipmaps = true;", - " texture.anisotropy = 4;", + " texture.anisotropy = anisotropy;", " texture.needsUpdate = true;", - " textures.set(imageTexture, texture);", + " texturesByAnisotropy.set(anisotropy, texture);", " }", " return texture;", "};", "", + "/** @type {Float32Array | null} */", + "let srgbToLinearValues = null;", + "/** @type {WeakMap} */", + "const linearAverageColors = new WeakMap();", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Vector3 | null} The average color of the texture, in the", + " * linear color space (like colors read by shaders), or null if the image", + " * can't be read: not loaded yet, or from another domain without CORS.", + " */", + "const getLinearAverageColor = (texture) => {", + " const image = texture.image;", + " if (!image) return null;", + " const cachedColor = linearAverageColors.get(image);", + " if (cachedColor) return cachedColor;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return null;", + " const size = 64;", + " let pixels;", + " try {", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " // Downscaled with filtering, so that all pixels are counted.", + " context.imageSmoothingEnabled = true;", + " context.imageSmoothingQuality = 'high';", + " context.drawImage(image, 0, 0, size, size);", + " pixels = context.getImageData(0, 0, size, size).data;", + " } catch (error) {", + " return null;", + " }", + " if (!srgbToLinearValues) {", + " srgbToLinearValues = new Float32Array(256);", + " for (let value = 0; value < 256; value++) {", + " const srgb = value / 255;", + " srgbToLinearValues[value] = srgb <= 0.04045 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);", + " }", + " }", + " const isSrgb = texture.colorSpace === THREE.SRGBColorSpace;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += isSrgb ? srgbToLinearValues[pixels[index]] : pixels[index] / 255;", + " green += isSrgb ? srgbToLinearValues[pixels[index + 1]] : pixels[index + 1] / 255;", + " blue += isSrgb ? srgbToLinearValues[pixels[index + 2]] : pixels[index + 2] / 255;", + " }", + " const count = size * size;", + " const color = new THREE.Vector3(red / count, green / count, blue / count);", + " linearAverageColors.set(image, color);", + " return color;", + "};", + "", "/**", " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", " * weights, tint and wetness...), interpolated between samples.", @@ -14038,11 +14146,14 @@ " terrainLayerMap1: { value: getWhiteTexture() },", " terrainLayerMap2: { value: getWhiteTexture() },", " terrainLayerMap3: { value: getWhiteTexture() },", + " // Used by the height blending, in the linear color space.", + " terrainLayerAverageColors: {", + " value: [new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1)],", + " },", " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", - " terrainHasNormalMaps: { value: 0 },", " terrainNormalMapStrength: { value: 1 },", " terrainTextureSize: { value: 256 },", " terrainHeightBlending: { value: 0 },", @@ -14051,6 +14162,7 @@ " terrainCliffCosines: { value: new THREE.Vector2() },", " terrainBrush: { value: new THREE.Vector4() },", " terrainColorMap: { value: getWhiteTexture() },", + " terrainNoiseMap: { value: getNoiseTexture() },", " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", " terrainWetShore: { value: new THREE.Vector3() },", " // Scene units by 3D world unit.", @@ -14070,8 +14182,12 @@ " ['#include ', '#include \\n' + fragmentShaderNormalCode],", " ], 'Terrain3D');", " };", - " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", " this.hasHoles = false;", + " /** The defines of the features used by the terrain (see `updateMaterial`), without holes. */", + " this.featureDefines = [];", + " /** All the defines of the shader, separated by semicolons. */", + " this.shaderKey = '';", + " this.material.customProgramCacheKey = () => 'Terrain3D;' + this.shaderKey;", " // Without them, holes would cast shadows.", " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", @@ -14108,11 +14224,28 @@ " setHasHoles(hasHoles) {", " if (hasHoles === this.hasHoles) return;", " this.hasHoles = hasHoles;", + " this._updateShaderDefines();", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /**", + " * Compile the shader only with the features used by the terrain. It is", + " * compiled again only when they change: properties only change in the", + " * editor, holes can be made by actions.", + " */", + " _updateShaderDefines() {", + " const defines = this.hasHoles ? [...this.featureDefines, 'TERRAIN_HOLES'] : this.featureDefines;", + " const shaderKey = defines.join(';');", + " if (shaderKey === this.shaderKey) return;", " // The material has its own defines (STANDARD).", - " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", - " else delete this.material.defines.TERRAIN_HOLES;", + " for (const name of this.shaderKey ? this.shaderKey.split(';') : []) {", + " delete this.material.defines[name];", + " }", + " for (const name of defines) {", + " this.material.defines[name] = '';", + " }", + " this.shaderKey = shaderKey;", " this.material.needsUpdate = true;", - " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", " }", "", " /** @param {THREE.Mesh} mesh */", @@ -14344,16 +14477,38 @@ " object._getLayer3NormalMap(),", " object._getLayer4NormalMap(),", " ];", + " const anisotropy = Math.max(parseInt(object._getAnisotropy(), 10) || DEFAULT_ANISOTROPY, 1);", + " const heightBlending = clamp01(object._getHeightBlending());", + " const textureVariation = clamp01(object._getTextureVariation());", + " const featureDefines = [];", " for (let layer = 0; layer < LAYER_COUNT; layer++) {", " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", - " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", - " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " const layerTexture = getLayerTexture(game, textures[layer], false, anisotropy);", + " this.uniforms['terrainLayerMap' + layer].value = layerTexture;", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true, anisotropy);", + " const averageColor = this.uniforms.terrainLayerAverageColors.value[layer];", + " if (textures[layer]) {", + " featureDefines.push('TERRAIN_LAYER_MAP_' + layer);", + " const linearAverageColor = heightBlending > 0 ? getLinearAverageColor(layerTexture) : null;", + " if (linearAverageColor) {", + " averageColor.copy(linearAverageColor);", + " } else if (heightBlending > 0) {", + " featureDefines.push('TERRAIN_LAYER_MIPMAP_AVERAGE_' + layer);", + " }", + " } else {", + " averageColor.set(1, 1, 1);", + " }", + " if (normalMaps[layer]) featureDefines.push('TERRAIN_LAYER_NORMAL_MAP_' + layer);", " }", - " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " if (normalMaps.some((normalMap) => !!normalMap)) featureDefines.push('TERRAIN_NORMAL_MAPS');", + " if (heightBlending > 0) featureDefines.push('TERRAIN_HEIGHT_BLENDING');", + " if (textureVariation > 0) featureDefines.push('TERRAIN_TEXTURE_VARIATION');", + " this.featureDefines = featureDefines;", + " this._updateShaderDefines();", " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", - " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", - " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + " this.uniforms.terrainHeightBlending.value = heightBlending;", + " this.uniforms.terrainTextureVariation.value = textureVariation;", "", " const cliffLayer = parseInt(object._getCliffLayer(), 10);", " const cliffAngle = gdjs.toRad(object._getCliffAngle());", @@ -15271,40 +15426,21 @@ " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", "};", "", + "/** @type {WeakMap} */", "const averageColors = new WeakMap();", "let white = null;", "/**", " * @param {THREE.Texture} texture", - " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " * @returns {THREE.Color} The average color of the texture (white when it can't be read).", " */", "const getAverageColor = (texture) => {", - " const cachedColor = averageColors.get(texture);", - " if (cachedColor) return cachedColor;", - " const image = texture.image;", - " const isDrawable =", - " typeof document !== 'undefined' &&", - " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", - " image instanceof HTMLCanvasElement ||", - " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", - " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", - " const size = 8;", - " const canvas = document.createElement('canvas');", - " canvas.width = size;", - " canvas.height = size;", - " const context = canvas.getContext('2d');", - " context.drawImage(image, 0, 0, size, size);", - " const pixels = context.getImageData(0, 0, size, size).data;", - " let red = 0;", - " let green = 0;", - " let blue = 0;", - " for (let index = 0; index < pixels.length; index += 4) {", - " red += pixels[index];", - " green += pixels[index + 1];", - " blue += pixels[index + 2];", + " const linearAverageColor = getLinearAverageColor(texture);", + " if (!linearAverageColor) return white || (white = new THREE.Color(1, 1, 1));", + " let color = averageColors.get(linearAverageColor);", + " if (!color) {", + " color = new THREE.Color(linearAverageColor.x, linearAverageColor.y, linearAverageColor.z);", + " averageColors.set(linearAverageColor, color);", " }", - " const count = size * size * 255;", - " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", - " averageColors.set(texture, color);", " return color;", "};", "", @@ -18918,6 +19054,37 @@ "group": "Rendering", "name": "ReceiveShadow" }, + { + "value": "4", + "type": "Choice", + "label": "Anisotropic filtering", + "description": "Keeps layer textures sharp where the ground is seen at a low angle (like from a car). Lower is faster on slow graphics cards, but blurs the ground in the distance.", + "group": "Rendering", + "choices": [ + { + "label": "None (fastest)", + "value": "1" + }, + { + "label": "2x", + "value": "2" + }, + { + "label": "4x", + "value": "4" + }, + { + "label": "8x", + "value": "8" + }, + { + "label": "16x (sharpest)", + "value": "16" + } + ], + "advanced": true, + "name": "Anisotropy" + }, { "value": "", "type": "String", @@ -19031,6 +19198,9 @@ }, { "propertyName": "ReceiveShadow" + }, + { + "propertyName": "Anisotropy" } ] }, diff --git a/examples/starting-3d-driving/theme-slots.json b/examples/starting-3d-driving/theme-slots.json index ed37222a2..d07dc324d 100644 --- a/examples/starting-3d-driving/theme-slots.json +++ b/examples/starting-3d-driving/theme-slots.json @@ -2,12 +2,26 @@ "version": 1, "objects": { "scene:Game Scene/Road_3D": "env.road", - "scene:Game Scene/Grass_3D": "env.ground", + "scene:Game Scene/Terrain": { + "Layer1Texture": { + "slot": "terrain.ground", + "normalMap": "Layer1NormalMap" + }, + "Layer2Texture": { + "slot": "terrain.road", + "normalMap": "Layer2NormalMap" + } + }, "scene:Game Scene/PlayerCar": "vehicle.car", "scene:Game Scene/TrafficCone": "prop.obstacle", "scene:Game Scene/Walls_3D": "env.wall" }, "effects": { "effect:Game Scene//SkyBox": "sky.day" - } + }, + "ignoredObjects": [ + "object:Terrain3D::Terrain3D/AreaPlaceholder", + "object:Terrain3D::TerrainGrass/AreaPlaceholder", + "object:Terrain3D::ScatteredModels/AreaPlaceholder" + ] } diff --git a/examples/starting-3d-grand-theft-auto/starting-3d-grand-theft-auto.json b/examples/starting-3d-grand-theft-auto/starting-3d-grand-theft-auto.json index 136cb142d..58449cd91 100644 --- a/examples/starting-3d-grand-theft-auto/starting-3d-grand-theft-auto.json +++ b/examples/starting-3d-grand-theft-auto/starting-3d-grand-theft-auto.json @@ -1956,6 +1956,51 @@ "source": "", "type": "BuiltinCommonInstructions::Group", "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Start with touch controls on touchscreens." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SceneJustBegins" + }, + "parameters": [ + "" + ] + }, + { + "type": { + "value": "SystemInfo::HasTouchScreen" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SpriteToggleSwitch::SpriteToggleSwitch::SetChecked" + }, + "parameters": [ + "ControlsToggle", + "yes", + "" + ] + } + ] + }, { "folded": true, "type": "BuiltinCommonInstructions::Standard", @@ -3187,18 +3232,11 @@ "conditions": [ { "type": { - "value": "MouseButtonFromTextPressed" + "value": "HasAnyTouchOrMouseStarted" }, "parameters": [ - "", - "\"Left\"" + "" ] - }, - { - "type": { - "value": "BuiltinCommonInstructions::Once" - }, - "parameters": [] } ], "actions": [], @@ -3219,17 +3257,6 @@ "" ] }, - { - "type": { - "inverted": true, - "value": "SpriteMultitouchJoystick::MultitouchButton::IsPressed" - }, - "parameters": [ - "JumpButton", - "MultitouchButton", - "" - ] - }, { "type": { "inverted": true, @@ -18760,7 +18787,6 @@ { "author": "PANDAKO-GitHub", "category": "Input", - "dimension": "", "extensionNamespace": "", "fullName": "Mouse Pointer Lock", "gdevelopVersion": ">=5.5.222", @@ -18769,7 +18795,7 @@ "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", - "version": "0.3.1", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -18817,7 +18843,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -19065,16 +19091,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -19257,6 +19313,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -19538,68 +19619,12 @@ "objectGroups": [] } ], - "eventsFunctionsFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "functionName": "onFirstSceneLoaded" - }, - { - "functionName": "onScenePostEvents" - }, - { - "functionName": "RequestPointerLock" - }, - { - "functionName": "ExitPointerLock" - }, - { - "functionName": "isPointerLocked" - }, - { - "functionName": "isPointerActuallyLocked" - }, - { - "functionName": "isEmulatingPointerLock" - }, - { - "functionName": "IsMoving" - }, - { - "functionName": "MovementX" - }, - { - "functionName": "SetMovementX" - }, - { - "functionName": "MovementY" - }, - { - "functionName": "SetMovementY" - }, - { - "functionName": "TouchX" - }, - { - "functionName": "TouchY" - }, - { - "functionName": "TouchSpeedFactor" - }, - { - "functionName": "SetTouchSpeedFactor" - } - ] - }, "eventsBasedBehaviors": [ { "description": "Control camera rotations with a mouse.", "fullName": "First person camera mouse mapper", - "helpPath": "", - "iconUrl": "", "name": "FirstPersonPointerMapper", "objectType": "", - "previewIconUrl": "", "eventsFunctions": [ { "fullName": "", @@ -19619,6 +19644,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -19640,7 +19677,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { @@ -19874,7 +19911,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "HorizontalSpeed", - "group": "First person camera mouse mapper configuration", "name": "SetHorizontalSpeed", "sentence": "", "events": [ @@ -19955,7 +19991,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalSpeed", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalSpeed", "sentence": "", "events": [ @@ -20036,7 +20071,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMin", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMin", "sentence": "", "events": [ @@ -20117,7 +20151,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMax", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMax", "sentence": "", "events": [ @@ -20198,7 +20231,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "OffsetZ", - "group": "First person camera mouse mapper configuration", "name": "SetOffsetZ", "sentence": "", "events": [ @@ -20235,57 +20267,6 @@ "objectGroups": [] } ], - "eventsFunctionsFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "functionName": "doStepPreEvents" - }, - { - "folderName": "Layers and cameras", - "children": [ - { - "functionName": "LookFromObjectEyes" - } - ] - }, - { - "folderName": "First person camera mouse mapper configuration", - "children": [ - { - "functionName": "HorizontalSpeed" - }, - { - "functionName": "SetHorizontalSpeed" - }, - { - "functionName": "VerticalSpeed" - }, - { - "functionName": "SetVerticalSpeed" - }, - { - "functionName": "VerticalAngleMin" - }, - { - "functionName": "SetVerticalAngleMin" - }, - { - "functionName": "VerticalAngleMax" - }, - { - "functionName": "SetVerticalAngleMax" - }, - { - "functionName": "OffsetZ" - }, - { - "functionName": "SetOffsetZ" - } - ] - } - ] - }, "propertyDescriptors": [ { "value": "", @@ -20339,32 +20320,7 @@ "name": "ShouldLock" } ], - "propertiesFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "propertyName": "Object3D" - }, - { - "propertyName": "HorizontalSpeed" - }, - { - "propertyName": "VerticalSpeed" - }, - { - "propertyName": "VerticalAngleMin" - }, - { - "propertyName": "VerticalAngleMax" - }, - { - "propertyName": "OffsetZ" - }, - { - "propertyName": "ShouldLock" - } - ] - } + "sharedPropertyDescriptors": [] } ], "eventsBasedObjects": [] @@ -28648,7 +28604,7 @@ "name": "Terrain3D", "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", - "version": "0.1.0", + "version": "0.2.0", "description": [ "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", "", @@ -29748,8 +29704,17 @@ "vTerrainLocalXY = position.xy;", "vTerrainLocalZ = position.z;", "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", - "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "// The world normal, from the camera space normal (computed by Three.js with a", + "// matrix inverted on the CPU), instead of inverting a matrix for each vertex.", + "vTerrainUp = inverseTransformDirection(transformedNormal, viewMatrix).z;", "`;", + "/** @param {(layer: number) => string} getLayerCode */", + "const forEachLayerCode = (getLayerCode) => [0, 1, 2, 3].map(getLayerCode).join('\\n');", + "", + "// Noise is read from a texture of random values, repeated every", + "// NOISE_MAP_SIZE units of noise: 1 texture read instead of 16 hashes.", + "const NOISE_MAP_SIZE = 256;", + "", "const fragmentShaderDeclarations = `", "uniform sampler2D terrainSplatMap;", "uniform vec2 terrainSplatUvScaleAndOffset;", @@ -29758,11 +29723,11 @@ "uniform sampler2D terrainLayerMap1;", "uniform sampler2D terrainLayerMap2;", "uniform sampler2D terrainLayerMap3;", + "uniform vec3 terrainLayerAverageColors[4];", "uniform sampler2D terrainLayerNormalMap0;", "uniform sampler2D terrainLayerNormalMap1;", "uniform sampler2D terrainLayerNormalMap2;", "uniform sampler2D terrainLayerNormalMap3;", - "uniform float terrainHasNormalMaps;", "uniform float terrainNormalMapStrength;", "uniform float terrainTextureSize;", "uniform float terrainHeightBlending;", @@ -29771,15 +29736,13 @@ "uniform vec2 terrainCliffCosines;", "uniform vec4 terrainBrush;", "uniform sampler2D terrainColorMap;", + "uniform sampler2D terrainNoiseMap;", "uniform vec3 terrainWetShore;", "varying vec2 vTerrainLocalXY;", "varying float vTerrainLocalZ;", "varying vec2 vTerrainWorldXY;", "varying float vTerrainUp;", "", - "float terrainHash(vec2 p) {", - " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", - "}", "// The rotation of the copies of textures used to make repetition less visible.", "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", @@ -29791,15 +29754,16 @@ " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", " return mix(bump, copyBump, patches);", "}", - "float terrainNoise(vec2 p) {", + "/**", + " * 4 independent value noises (one by channel), from 0 to 1, smoothly varying", + " * between random values at integer positions.", + " */", + "vec4 terrainNoise(vec2 p) {", " vec2 i = floor(p);", - " vec2 f = fract(p);", - " vec2 u = f * f * (3.0 - 2.0 * f);", - " return mix(", - " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", - " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", - " u.y", - " );", + " vec2 f = p - i;", + " // The read position is moved so that the linear interpolation of the", + " // texture between 2 random values becomes a smooth one.", + " return texture2D(terrainNoiseMap, (i + f * f * (3.0 - 2.0 * f) + 0.5) / ${NOISE_MAP_SIZE}.0);", "}", "`;", "// Holes are samples without any painted layer: the interpolated sum of the", @@ -29817,15 +29781,11 @@ "varying vec2 vTerrainLocalXY;", "`;", "", + "// Layers without texture, normal map, height blending or texture variation", + "// are compiled out (see TerrainRenderer.updateMaterial).", "const fragmentShaderCode = holeShaderCode + `", "// Borders between layers are made irregular and sharper, to look painted.", - "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", - "vec4 terrainJitter = vec4(", - " terrainNoise(terrainNoisePosition),", - " terrainNoise(terrainNoisePosition + 19.1),", - " terrainNoise(terrainNoisePosition + 37.7),", - " terrainNoise(terrainNoisePosition + 53.3)", - ");", + "vec4 terrainJitter = terrainNoise(vTerrainWorldXY / 24.0);", "// Layer weights are in a texture, so that painted details stay the same", "// whatever the level of detail of the ground.", "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", @@ -29836,48 +29796,61 @@ "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", "", "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", - "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", - "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", - "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", - "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "vec3 terrainTexture${layer} = texture2D(terrainLayerMap${layer}, terrainUv).rgb;", + "#else", + "vec3 terrainTexture${layer} = vec3(1.0);", + "#endif`", + ")}", "", "// Less visible repetition: in irregular patches, textures are replaced by a", "// rotated and shifted copy of themselves, and colors slowly vary.", "float terrainPatches = 0.0;", "vec2 terrainUv2 = terrainUv;", "float terrainColorVariation = 1.0;", - "if (terrainTextureVariation > 0.0) {", - " // Up to half of the ground is covered by the copies, each patch showing", - " // only one of them (mixing them would make them blurry).", - " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", - " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", - " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", - " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", - " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", - " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", - " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", - " terrainColorVariation += terrainTextureVariation * 0.3 *", - " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", - "}", + "#ifdef TERRAIN_TEXTURE_VARIATION", + "// Up to half of the ground is covered by the copies, each patch showing", + "// only one of them (mixing them would make them blurry).", + "float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + "terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3).x);", + "terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "terrainTexture${layer} = mix(terrainTexture${layer}, texture2D(terrainLayerMap${layer}, terrainUv2).rgb, terrainPatches);", + "#endif`", + ")}", + "terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11).y + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1).z - 0.75);", + "#endif", "", "// Height-based blending: the brightness of a texture, compared to its", "// average, is used as its height. Where layers meet, the high parts (stones,", "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", - "if (terrainHeightBlending > 0.0) {", - " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", - " vec4 terrainHeights = vec4(", - " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", - " );", - " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", - " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", - " // Only painted layers (and the cliff layer) can show.", - " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", - " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", - " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", - "}", + "#ifdef TERRAIN_HEIGHT_BLENDING", + "// Averages are computed once on the CPU, or read from the smallest mipmap", + "// when the image can't be read by the CPU.", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MIPMAP_AVERAGE_${layer}", + "vec3 terrainAverage${layer} = textureLod(terrainLayerMap${layer}, vec2(0.5), 16.0).rgb;", + "#else", + "vec3 terrainAverage${layer} = terrainLayerAverageColors[${layer}];", + "#endif`", + ")}", + "const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + "vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - terrainAverage0, terrainLuminance),", + " dot(terrainTexture1 - terrainAverage1, terrainLuminance),", + " dot(terrainTexture2 - terrainAverage2, terrainLuminance),", + " dot(terrainTexture3 - terrainAverage3, terrainLuminance)", + ");", + "vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + "float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + "// Only painted layers (and the cliff layer) can show.", + "vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + "terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + "terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "#endif", "", "vec3 terrainColor = terrainColorVariation * (", " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", @@ -29909,26 +29882,30 @@ "`;", "", "const fragmentShaderNormalCode = `", - "if (terrainHasNormalMaps > 0.5) {", - " vec3 terrainMapNormal =", - " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", - " terrainMapNormal.xy *= terrainNormalMapStrength;", - " // The X and Y of textures follow the X and Y of the 3D world, projected on", - " // the ground (the camera space of the normal is used).", - " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "#ifdef TERRAIN_NORMAL_MAPS", + "// Layers without normal map are flat.", + "vec3 terrainMapNormal = vec3(0.0);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_NORMAL_MAP_${layer}", + "terrainMapNormal += terrainWeights[${layer}] * terrainSampleNormal(terrainLayerNormalMap${layer}, terrainUv, terrainUv2, terrainPatches);", + "#else", + "terrainMapNormal.z += terrainWeights[${layer}];", + "#endif`", + ")}", + "terrainMapNormal.xy *= terrainNormalMapStrength;", + "// The X and Y of textures follow the X and Y of the 3D world, projected on", + "// the ground (the camera space of the normal is used).", + "vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "terrainTangent -= normal * dot(normal, terrainTangent);", + "// A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + "if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", " terrainTangent -= normal * dot(normal, terrainTangent);", - " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", - " if (dot(terrainTangent, terrainTangent) < 0.000001) {", - " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", - " terrainTangent -= normal * dot(normal, terrainTangent);", - " }", - " terrainTangent = normalize(terrainTangent);", - " vec3 terrainBitangent = cross(normal, terrainTangent);", - " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", "}", + "terrainTangent = normalize(terrainTangent);", + "vec3 terrainBitangent = cross(normal, terrainTangent);", + "normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "#endif", "`;", "", "let whiteTexture = null;", @@ -29949,7 +29926,30 @@ " return flatNormalTexture;", "};", "", + "let noiseTexture = null;", + "/** Random values, in 4 independent channels, read by `terrainNoise` in the shader. */", + "const getNoiseTexture = () => {", + " if (!noiseTexture) {", + " const random = createRandom(1);", + " const bytes = new Uint8Array(NOISE_MAP_SIZE * NOISE_MAP_SIZE * 4);", + " for (let index = 0; index < bytes.length; index++) {", + " bytes[index] = Math.floor(random() * 256);", + " }", + " noiseTexture = new THREE.DataTexture(bytes, NOISE_MAP_SIZE, NOISE_MAP_SIZE);", + " noiseTexture.wrapS = THREE.RepeatWrapping;", + " noiseTexture.wrapT = THREE.RepeatWrapping;", + " // No mipmaps: the shader moves the read position between samples.", + " noiseTexture.magFilter = THREE.LinearFilter;", + " noiseTexture.minFilter = THREE.LinearFilter;", + " noiseTexture.needsUpdate = true;", + " }", + " return noiseTexture;", + "};", + "", + "const DEFAULT_ANISOTROPY = 4;", + "/** @type {WeakMap>} */", "const layerTextures = new WeakMap();", + "/** @type {WeakMap>} */", "const layerNormalMaps = new WeakMap();", "/**", " * Textures of the image manager have no mipmaps: they would shimmer when", @@ -29957,12 +29957,18 @@ " * @param {gdjs.RuntimeGame} game", " * @param {string} resourceName", " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " * @param {number} anisotropy", " */", - "const getLayerTexture = (game, resourceName, isNormalMap) => {", + "const getLayerTexture = (game, resourceName, isNormalMap, anisotropy) => {", " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", - " const textures = isNormalMap ? layerNormalMaps : layerTextures;", - " let texture = textures.get(imageTexture);", + " const texturesByImage = isNormalMap ? layerNormalMaps : layerTextures;", + " let texturesByAnisotropy = texturesByImage.get(imageTexture);", + " if (!texturesByAnisotropy) {", + " texturesByAnisotropy = new Map();", + " texturesByImage.set(imageTexture, texturesByAnisotropy);", + " }", + " let texture = texturesByAnisotropy.get(anisotropy);", " if (!texture) {", " texture = imageTexture.clone();", " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", @@ -29970,13 +29976,71 @@ " texture.wrapT = THREE.RepeatWrapping;", " texture.minFilter = THREE.LinearMipmapLinearFilter;", " texture.generateMipmaps = true;", - " texture.anisotropy = 4;", + " texture.anisotropy = anisotropy;", " texture.needsUpdate = true;", - " textures.set(imageTexture, texture);", + " texturesByAnisotropy.set(anisotropy, texture);", " }", " return texture;", "};", "", + "/** @type {Float32Array | null} */", + "let srgbToLinearValues = null;", + "/** @type {WeakMap} */", + "const linearAverageColors = new WeakMap();", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Vector3 | null} The average color of the texture, in the", + " * linear color space (like colors read by shaders), or null if the image", + " * can't be read: not loaded yet, or from another domain without CORS.", + " */", + "const getLinearAverageColor = (texture) => {", + " const image = texture.image;", + " if (!image) return null;", + " const cachedColor = linearAverageColors.get(image);", + " if (cachedColor) return cachedColor;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return null;", + " const size = 64;", + " let pixels;", + " try {", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " // Downscaled with filtering, so that all pixels are counted.", + " context.imageSmoothingEnabled = true;", + " context.imageSmoothingQuality = 'high';", + " context.drawImage(image, 0, 0, size, size);", + " pixels = context.getImageData(0, 0, size, size).data;", + " } catch (error) {", + " return null;", + " }", + " if (!srgbToLinearValues) {", + " srgbToLinearValues = new Float32Array(256);", + " for (let value = 0; value < 256; value++) {", + " const srgb = value / 255;", + " srgbToLinearValues[value] = srgb <= 0.04045 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);", + " }", + " }", + " const isSrgb = texture.colorSpace === THREE.SRGBColorSpace;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += isSrgb ? srgbToLinearValues[pixels[index]] : pixels[index] / 255;", + " green += isSrgb ? srgbToLinearValues[pixels[index + 1]] : pixels[index + 1] / 255;", + " blue += isSrgb ? srgbToLinearValues[pixels[index + 2]] : pixels[index + 2] / 255;", + " }", + " const count = size * size;", + " const color = new THREE.Vector3(red / count, green / count, blue / count);", + " linearAverageColors.set(image, color);", + " return color;", + "};", + "", "/**", " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", " * weights, tint and wetness...), interpolated between samples.", @@ -30035,11 +30099,14 @@ " terrainLayerMap1: { value: getWhiteTexture() },", " terrainLayerMap2: { value: getWhiteTexture() },", " terrainLayerMap3: { value: getWhiteTexture() },", + " // Used by the height blending, in the linear color space.", + " terrainLayerAverageColors: {", + " value: [new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1)],", + " },", " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", - " terrainHasNormalMaps: { value: 0 },", " terrainNormalMapStrength: { value: 1 },", " terrainTextureSize: { value: 256 },", " terrainHeightBlending: { value: 0 },", @@ -30048,6 +30115,7 @@ " terrainCliffCosines: { value: new THREE.Vector2() },", " terrainBrush: { value: new THREE.Vector4() },", " terrainColorMap: { value: getWhiteTexture() },", + " terrainNoiseMap: { value: getNoiseTexture() },", " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", " terrainWetShore: { value: new THREE.Vector3() },", " // Scene units by 3D world unit.", @@ -30067,8 +30135,12 @@ " ['#include ', '#include \\n' + fragmentShaderNormalCode],", " ], 'Terrain3D');", " };", - " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", " this.hasHoles = false;", + " /** The defines of the features used by the terrain (see `updateMaterial`), without holes. */", + " this.featureDefines = [];", + " /** All the defines of the shader, separated by semicolons. */", + " this.shaderKey = '';", + " this.material.customProgramCacheKey = () => 'Terrain3D;' + this.shaderKey;", " // Without them, holes would cast shadows.", " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", @@ -30105,11 +30177,28 @@ " setHasHoles(hasHoles) {", " if (hasHoles === this.hasHoles) return;", " this.hasHoles = hasHoles;", + " this._updateShaderDefines();", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /**", + " * Compile the shader only with the features used by the terrain. It is", + " * compiled again only when they change: properties only change in the", + " * editor, holes can be made by actions.", + " */", + " _updateShaderDefines() {", + " const defines = this.hasHoles ? [...this.featureDefines, 'TERRAIN_HOLES'] : this.featureDefines;", + " const shaderKey = defines.join(';');", + " if (shaderKey === this.shaderKey) return;", " // The material has its own defines (STANDARD).", - " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", - " else delete this.material.defines.TERRAIN_HOLES;", + " for (const name of this.shaderKey ? this.shaderKey.split(';') : []) {", + " delete this.material.defines[name];", + " }", + " for (const name of defines) {", + " this.material.defines[name] = '';", + " }", + " this.shaderKey = shaderKey;", " this.material.needsUpdate = true;", - " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", " }", "", " /** @param {THREE.Mesh} mesh */", @@ -30341,16 +30430,38 @@ " object._getLayer3NormalMap(),", " object._getLayer4NormalMap(),", " ];", + " const anisotropy = Math.max(parseInt(object._getAnisotropy(), 10) || DEFAULT_ANISOTROPY, 1);", + " const heightBlending = clamp01(object._getHeightBlending());", + " const textureVariation = clamp01(object._getTextureVariation());", + " const featureDefines = [];", " for (let layer = 0; layer < LAYER_COUNT; layer++) {", " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", - " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", - " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " const layerTexture = getLayerTexture(game, textures[layer], false, anisotropy);", + " this.uniforms['terrainLayerMap' + layer].value = layerTexture;", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true, anisotropy);", + " const averageColor = this.uniforms.terrainLayerAverageColors.value[layer];", + " if (textures[layer]) {", + " featureDefines.push('TERRAIN_LAYER_MAP_' + layer);", + " const linearAverageColor = heightBlending > 0 ? getLinearAverageColor(layerTexture) : null;", + " if (linearAverageColor) {", + " averageColor.copy(linearAverageColor);", + " } else if (heightBlending > 0) {", + " featureDefines.push('TERRAIN_LAYER_MIPMAP_AVERAGE_' + layer);", + " }", + " } else {", + " averageColor.set(1, 1, 1);", + " }", + " if (normalMaps[layer]) featureDefines.push('TERRAIN_LAYER_NORMAL_MAP_' + layer);", " }", - " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " if (normalMaps.some((normalMap) => !!normalMap)) featureDefines.push('TERRAIN_NORMAL_MAPS');", + " if (heightBlending > 0) featureDefines.push('TERRAIN_HEIGHT_BLENDING');", + " if (textureVariation > 0) featureDefines.push('TERRAIN_TEXTURE_VARIATION');", + " this.featureDefines = featureDefines;", + " this._updateShaderDefines();", " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", - " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", - " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + " this.uniforms.terrainHeightBlending.value = heightBlending;", + " this.uniforms.terrainTextureVariation.value = textureVariation;", "", " const cliffLayer = parseInt(object._getCliffLayer(), 10);", " const cliffAngle = gdjs.toRad(object._getCliffAngle());", @@ -31268,40 +31379,21 @@ " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", "};", "", + "/** @type {WeakMap} */", "const averageColors = new WeakMap();", "let white = null;", "/**", " * @param {THREE.Texture} texture", - " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " * @returns {THREE.Color} The average color of the texture (white when it can't be read).", " */", "const getAverageColor = (texture) => {", - " const cachedColor = averageColors.get(texture);", - " if (cachedColor) return cachedColor;", - " const image = texture.image;", - " const isDrawable =", - " typeof document !== 'undefined' &&", - " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", - " image instanceof HTMLCanvasElement ||", - " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", - " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", - " const size = 8;", - " const canvas = document.createElement('canvas');", - " canvas.width = size;", - " canvas.height = size;", - " const context = canvas.getContext('2d');", - " context.drawImage(image, 0, 0, size, size);", - " const pixels = context.getImageData(0, 0, size, size).data;", - " let red = 0;", - " let green = 0;", - " let blue = 0;", - " for (let index = 0; index < pixels.length; index += 4) {", - " red += pixels[index];", - " green += pixels[index + 1];", - " blue += pixels[index + 2];", + " const linearAverageColor = getLinearAverageColor(texture);", + " if (!linearAverageColor) return white || (white = new THREE.Color(1, 1, 1));", + " let color = averageColors.get(linearAverageColor);", + " if (!color) {", + " color = new THREE.Color(linearAverageColor.x, linearAverageColor.y, linearAverageColor.z);", + " averageColors.set(linearAverageColor, color);", " }", - " const count = size * size * 255;", - " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", - " averageColors.set(texture, color);", " return color;", "};", "", @@ -34915,6 +35007,37 @@ "group": "Rendering", "name": "ReceiveShadow" }, + { + "value": "4", + "type": "Choice", + "label": "Anisotropic filtering", + "description": "Keeps layer textures sharp where the ground is seen at a low angle (like from a car). Lower is faster on slow graphics cards, but blurs the ground in the distance.", + "group": "Rendering", + "choices": [ + { + "label": "None (fastest)", + "value": "1" + }, + { + "label": "2x", + "value": "2" + }, + { + "label": "4x", + "value": "4" + }, + { + "label": "8x", + "value": "8" + }, + { + "label": "16x (sharpest)", + "value": "16" + } + ], + "advanced": true, + "name": "Anisotropy" + }, { "value": "", "type": "String", @@ -35028,6 +35151,9 @@ }, { "propertyName": "ReceiveShadow" + }, + { + "propertyName": "Anisotropy" } ] }, diff --git a/examples/starting-3d-grand-theft-auto/theme-slots.json b/examples/starting-3d-grand-theft-auto/theme-slots.json index 33706862e..728049021 100644 --- a/examples/starting-3d-grand-theft-auto/theme-slots.json +++ b/examples/starting-3d-grand-theft-auto/theme-slots.json @@ -6,15 +6,19 @@ "scene:Game Scene/Driven_Car": "vehicle.car", "scene:Game Scene/PushableBox": "env.crate", "scene:Game Scene/Obstacle": "env.wall", - "scene:Game Scene/Ground": { - "front": "env.ground", - "left": "env.wall", - "right": "env.wall", - "top": "env.wall", - "bottom": "env.wall" + "scene:Game Scene/Terrain": { + "Layer1Texture": { + "slot": "terrain.ground", + "normalMap": "Layer1NormalMap" + } } }, "effects": { "effect:Game Scene//SkyBox": "sky.day" - } + }, + "ignoredObjects": [ + "object:Terrain3D::Terrain3D/AreaPlaceholder", + "object:Terrain3D::TerrainGrass/AreaPlaceholder", + "object:Terrain3D::ScatteredModels/AreaPlaceholder" + ] } diff --git a/examples/starting-3d-tank/starting-3d-tank.json b/examples/starting-3d-tank/starting-3d-tank.json index 819928141..951c62993 100644 --- a/examples/starting-3d-tank/starting-3d-tank.json +++ b/examples/starting-3d-tank/starting-3d-tank.json @@ -36268,7 +36268,7 @@ "name": "Terrain3D", "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/10e0a26c0d500830dfe23b94138beb0ef61607ba62bca05a5aa5c849777f1b06_terrain.svg", "shortDescription": "A ground with hills and valleys that can be sculpted and painted in the editor, with collisions.", - "version": "0.1.0", + "version": "0.2.0", "description": [ "A 3D terrain object for open worlds, adventure or racing games: hills, mountains, islands or valleys, with painted layers of grass, dirt, rock or sand.", "", @@ -37368,8 +37368,17 @@ "vTerrainLocalXY = position.xy;", "vTerrainLocalZ = position.z;", "vTerrainWorldXY = (modelMatrix * vec4(transformed, 1.0)).xy * terrainWorldScale;", - "vTerrainUp = normalize(transpose(inverse(mat3(modelMatrix))) * objectNormal).z;", + "// The world normal, from the camera space normal (computed by Three.js with a", + "// matrix inverted on the CPU), instead of inverting a matrix for each vertex.", + "vTerrainUp = inverseTransformDirection(transformedNormal, viewMatrix).z;", "`;", + "/** @param {(layer: number) => string} getLayerCode */", + "const forEachLayerCode = (getLayerCode) => [0, 1, 2, 3].map(getLayerCode).join('\\n');", + "", + "// Noise is read from a texture of random values, repeated every", + "// NOISE_MAP_SIZE units of noise: 1 texture read instead of 16 hashes.", + "const NOISE_MAP_SIZE = 256;", + "", "const fragmentShaderDeclarations = `", "uniform sampler2D terrainSplatMap;", "uniform vec2 terrainSplatUvScaleAndOffset;", @@ -37378,11 +37387,11 @@ "uniform sampler2D terrainLayerMap1;", "uniform sampler2D terrainLayerMap2;", "uniform sampler2D terrainLayerMap3;", + "uniform vec3 terrainLayerAverageColors[4];", "uniform sampler2D terrainLayerNormalMap0;", "uniform sampler2D terrainLayerNormalMap1;", "uniform sampler2D terrainLayerNormalMap2;", "uniform sampler2D terrainLayerNormalMap3;", - "uniform float terrainHasNormalMaps;", "uniform float terrainNormalMapStrength;", "uniform float terrainTextureSize;", "uniform float terrainHeightBlending;", @@ -37391,15 +37400,13 @@ "uniform vec2 terrainCliffCosines;", "uniform vec4 terrainBrush;", "uniform sampler2D terrainColorMap;", + "uniform sampler2D terrainNoiseMap;", "uniform vec3 terrainWetShore;", "varying vec2 vTerrainLocalXY;", "varying float vTerrainLocalZ;", "varying vec2 vTerrainWorldXY;", "varying float vTerrainUp;", "", - "float terrainHash(vec2 p) {", - " return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453);", - "}", "// The rotation of the copies of textures used to make repetition less visible.", "const mat2 terrainCopyRotation = mat2(0.8, -0.6, 0.6, 0.8);", "/** A bump of a normal map (from -1 to 1), mixed with its rotated copy in patches. */", @@ -37411,15 +37418,16 @@ " copyBump.xy = transpose(terrainCopyRotation) * copyBump.xy;", " return mix(bump, copyBump, patches);", "}", - "float terrainNoise(vec2 p) {", + "/**", + " * 4 independent value noises (one by channel), from 0 to 1, smoothly varying", + " * between random values at integer positions.", + " */", + "vec4 terrainNoise(vec2 p) {", " vec2 i = floor(p);", - " vec2 f = fract(p);", - " vec2 u = f * f * (3.0 - 2.0 * f);", - " return mix(", - " mix(terrainHash(i), terrainHash(i + vec2(1.0, 0.0)), u.x),", - " mix(terrainHash(i + vec2(0.0, 1.0)), terrainHash(i + vec2(1.0, 1.0)), u.x),", - " u.y", - " );", + " vec2 f = p - i;", + " // The read position is moved so that the linear interpolation of the", + " // texture between 2 random values becomes a smooth one.", + " return texture2D(terrainNoiseMap, (i + f * f * (3.0 - 2.0 * f) + 0.5) / ${NOISE_MAP_SIZE}.0);", "}", "`;", "// Holes are samples without any painted layer: the interpolated sum of the", @@ -37437,15 +37445,11 @@ "varying vec2 vTerrainLocalXY;", "`;", "", + "// Layers without texture, normal map, height blending or texture variation", + "// are compiled out (see TerrainRenderer.updateMaterial).", "const fragmentShaderCode = holeShaderCode + `", "// Borders between layers are made irregular and sharper, to look painted.", - "vec2 terrainNoisePosition = vTerrainWorldXY / 24.0;", - "vec4 terrainJitter = vec4(", - " terrainNoise(terrainNoisePosition),", - " terrainNoise(terrainNoisePosition + 19.1),", - " terrainNoise(terrainNoisePosition + 37.7),", - " terrainNoise(terrainNoisePosition + 53.3)", - ");", + "vec4 terrainJitter = terrainNoise(vTerrainWorldXY / 24.0);", "// Layer weights are in a texture, so that painted details stay the same", "// whatever the level of detail of the ground.", "vec2 terrainSplatUv = vTerrainLocalXY * terrainSplatUvScaleAndOffset.x + terrainSplatUvScaleAndOffset.y;", @@ -37456,48 +37460,61 @@ "terrainWeights = mix(terrainWeights, terrainCliffLayer, terrainCliff * dot(terrainCliffLayer, vec4(1.0)));", "", "vec2 terrainUv = vTerrainWorldXY / terrainTextureSize;", - "vec3 terrainTexture0 = texture2D(terrainLayerMap0, terrainUv).rgb;", - "vec3 terrainTexture1 = texture2D(terrainLayerMap1, terrainUv).rgb;", - "vec3 terrainTexture2 = texture2D(terrainLayerMap2, terrainUv).rgb;", - "vec3 terrainTexture3 = texture2D(terrainLayerMap3, terrainUv).rgb;", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "vec3 terrainTexture${layer} = texture2D(terrainLayerMap${layer}, terrainUv).rgb;", + "#else", + "vec3 terrainTexture${layer} = vec3(1.0);", + "#endif`", + ")}", "", "// Less visible repetition: in irregular patches, textures are replaced by a", "// rotated and shifted copy of themselves, and colors slowly vary.", "float terrainPatches = 0.0;", "vec2 terrainUv2 = terrainUv;", "float terrainColorVariation = 1.0;", - "if (terrainTextureVariation > 0.0) {", - " // Up to half of the ground is covered by the copies, each patch showing", - " // only one of them (mixing them would make them blurry).", - " float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", - " terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3));", - " terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", - " terrainTexture0 = mix(terrainTexture0, texture2D(terrainLayerMap0, terrainUv2).rgb, terrainPatches);", - " terrainTexture1 = mix(terrainTexture1, texture2D(terrainLayerMap1, terrainUv2).rgb, terrainPatches);", - " terrainTexture2 = mix(terrainTexture2, texture2D(terrainLayerMap2, terrainUv2).rgb, terrainPatches);", - " terrainTexture3 = mix(terrainTexture3, texture2D(terrainLayerMap3, terrainUv2).rgb, terrainPatches);", - " terrainColorVariation += terrainTextureVariation * 0.3 *", - " (terrainNoise(terrainUv * 0.11) + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1) - 0.75);", - "}", + "#ifdef TERRAIN_TEXTURE_VARIATION", + "// Up to half of the ground is covered by the copies, each patch showing", + "// only one of them (mixing them would make them blurry).", + "float terrainPatchThreshold = 1.0 - 0.5 * terrainTextureVariation;", + "terrainPatches = smoothstep(terrainPatchThreshold - 0.05, terrainPatchThreshold + 0.05, terrainNoise(terrainUv * 0.23 + 7.3).x);", + "terrainUv2 = terrainCopyRotation * terrainUv + vec2(0.31, 0.73);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MAP_${layer}", + "terrainTexture${layer} = mix(terrainTexture${layer}, texture2D(terrainLayerMap${layer}, terrainUv2).rgb, terrainPatches);", + "#endif`", + ")}", + "terrainColorVariation += terrainTextureVariation * 0.3 *", + " (terrainNoise(terrainUv * 0.11).y + 0.5 * terrainNoise(terrainUv * 0.37 + 3.1).z - 0.75);", + "#endif", "", "// Height-based blending: the brightness of a texture, compared to its", "// average, is used as its height. Where layers meet, the high parts (stones,", "// tufts) cover the low parts (sand, gaps) instead of fading into each other.", - "if (terrainHeightBlending > 0.0) {", - " const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", - " vec4 terrainHeights = vec4(", - " dot(terrainTexture0 - textureLod(terrainLayerMap0, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture1 - textureLod(terrainLayerMap1, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture2 - textureLod(terrainLayerMap2, vec2(0.5), 16.0).rgb, terrainLuminance),", - " dot(terrainTexture3 - textureLod(terrainLayerMap3, vec2(0.5), 16.0).rgb, terrainLuminance)", - " );", - " vec4 terrainHeightWeights = terrainWeights + terrainHeights;", - " float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", - " // Only painted layers (and the cliff layer) can show.", - " vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", - " terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", - " terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", - "}", + "#ifdef TERRAIN_HEIGHT_BLENDING", + "// Averages are computed once on the CPU, or read from the smallest mipmap", + "// when the image can't be read by the CPU.", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_MIPMAP_AVERAGE_${layer}", + "vec3 terrainAverage${layer} = textureLod(terrainLayerMap${layer}, vec2(0.5), 16.0).rgb;", + "#else", + "vec3 terrainAverage${layer} = terrainLayerAverageColors[${layer}];", + "#endif`", + ")}", + "const vec3 terrainLuminance = vec3(0.299, 0.587, 0.114);", + "vec4 terrainHeights = vec4(", + " dot(terrainTexture0 - terrainAverage0, terrainLuminance),", + " dot(terrainTexture1 - terrainAverage1, terrainLuminance),", + " dot(terrainTexture2 - terrainAverage2, terrainLuminance),", + " dot(terrainTexture3 - terrainAverage3, terrainLuminance)", + ");", + "vec4 terrainHeightWeights = terrainWeights + terrainHeights;", + "float terrainTop = max(max(terrainHeightWeights.x, terrainHeightWeights.y), max(terrainHeightWeights.z, terrainHeightWeights.w));", + "// Only painted layers (and the cliff layer) can show.", + "vec4 terrainHeightBlend = max(terrainHeightWeights - terrainTop + 0.1, 0.0) * step(0.004, terrainWeights);", + "terrainHeightBlend /= max(dot(terrainHeightBlend, vec4(1.0)), 0.00001);", + "terrainWeights = mix(terrainWeights, terrainHeightBlend, terrainHeightBlending);", + "#endif", "", "vec3 terrainColor = terrainColorVariation * (", " terrainWeights.x * terrainLayerColors[0] * terrainTexture0 +", @@ -37529,26 +37546,30 @@ "`;", "", "const fragmentShaderNormalCode = `", - "if (terrainHasNormalMaps > 0.5) {", - " vec3 terrainMapNormal =", - " terrainWeights.x * terrainSampleNormal(terrainLayerNormalMap0, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.y * terrainSampleNormal(terrainLayerNormalMap1, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.z * terrainSampleNormal(terrainLayerNormalMap2, terrainUv, terrainUv2, terrainPatches) +", - " terrainWeights.w * terrainSampleNormal(terrainLayerNormalMap3, terrainUv, terrainUv2, terrainPatches);", - " terrainMapNormal.xy *= terrainNormalMapStrength;", - " // The X and Y of textures follow the X and Y of the 3D world, projected on", - " // the ground (the camera space of the normal is used).", - " vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "#ifdef TERRAIN_NORMAL_MAPS", + "// Layers without normal map are flat.", + "vec3 terrainMapNormal = vec3(0.0);", + "${forEachLayerCode(", + " (layer) => `#ifdef TERRAIN_LAYER_NORMAL_MAP_${layer}", + "terrainMapNormal += terrainWeights[${layer}] * terrainSampleNormal(terrainLayerNormalMap${layer}, terrainUv, terrainUv2, terrainPatches);", + "#else", + "terrainMapNormal.z += terrainWeights[${layer}];", + "#endif`", + ")}", + "terrainMapNormal.xy *= terrainNormalMapStrength;", + "// The X and Y of textures follow the X and Y of the 3D world, projected on", + "// the ground (the camera space of the normal is used).", + "vec3 terrainTangent = (viewMatrix * vec4(1.0, 0.0, 0.0, 0.0)).xyz;", + "terrainTangent -= normal * dot(normal, terrainTangent);", + "// A ground facing the X axis (a rotated terrain) uses the Y axis instead.", + "if (dot(terrainTangent, terrainTangent) < 0.000001) {", + " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", " terrainTangent -= normal * dot(normal, terrainTangent);", - " // A ground facing the X axis (a rotated terrain) uses the Y axis instead.", - " if (dot(terrainTangent, terrainTangent) < 0.000001) {", - " terrainTangent = (viewMatrix * vec4(0.0, 1.0, 0.0, 0.0)).xyz;", - " terrainTangent -= normal * dot(normal, terrainTangent);", - " }", - " terrainTangent = normalize(terrainTangent);", - " vec3 terrainBitangent = cross(normal, terrainTangent);", - " normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", "}", + "terrainTangent = normalize(terrainTangent);", + "vec3 terrainBitangent = cross(normal, terrainTangent);", + "normal = normalize(mat3(terrainTangent, terrainBitangent, normal) * terrainMapNormal);", + "#endif", "`;", "", "let whiteTexture = null;", @@ -37569,7 +37590,30 @@ " return flatNormalTexture;", "};", "", + "let noiseTexture = null;", + "/** Random values, in 4 independent channels, read by `terrainNoise` in the shader. */", + "const getNoiseTexture = () => {", + " if (!noiseTexture) {", + " const random = createRandom(1);", + " const bytes = new Uint8Array(NOISE_MAP_SIZE * NOISE_MAP_SIZE * 4);", + " for (let index = 0; index < bytes.length; index++) {", + " bytes[index] = Math.floor(random() * 256);", + " }", + " noiseTexture = new THREE.DataTexture(bytes, NOISE_MAP_SIZE, NOISE_MAP_SIZE);", + " noiseTexture.wrapS = THREE.RepeatWrapping;", + " noiseTexture.wrapT = THREE.RepeatWrapping;", + " // No mipmaps: the shader moves the read position between samples.", + " noiseTexture.magFilter = THREE.LinearFilter;", + " noiseTexture.minFilter = THREE.LinearFilter;", + " noiseTexture.needsUpdate = true;", + " }", + " return noiseTexture;", + "};", + "", + "const DEFAULT_ANISOTROPY = 4;", + "/** @type {WeakMap>} */", "const layerTextures = new WeakMap();", + "/** @type {WeakMap>} */", "const layerNormalMaps = new WeakMap();", "/**", " * Textures of the image manager have no mipmaps: they would shimmer when", @@ -37577,12 +37621,18 @@ " * @param {gdjs.RuntimeGame} game", " * @param {string} resourceName", " * @param {boolean} isNormalMap Normal maps are directions, not colors.", + " * @param {number} anisotropy", " */", - "const getLayerTexture = (game, resourceName, isNormalMap) => {", + "const getLayerTexture = (game, resourceName, isNormalMap, anisotropy) => {", " if (!resourceName) return isNormalMap ? getFlatNormalTexture() : getWhiteTexture();", " const imageTexture = game.getImageManager().getThreeTexture(resourceName);", - " const textures = isNormalMap ? layerNormalMaps : layerTextures;", - " let texture = textures.get(imageTexture);", + " const texturesByImage = isNormalMap ? layerNormalMaps : layerTextures;", + " let texturesByAnisotropy = texturesByImage.get(imageTexture);", + " if (!texturesByAnisotropy) {", + " texturesByAnisotropy = new Map();", + " texturesByImage.set(imageTexture, texturesByAnisotropy);", + " }", + " let texture = texturesByAnisotropy.get(anisotropy);", " if (!texture) {", " texture = imageTexture.clone();", " if (isNormalMap) texture.colorSpace = THREE.NoColorSpace;", @@ -37590,13 +37640,71 @@ " texture.wrapT = THREE.RepeatWrapping;", " texture.minFilter = THREE.LinearMipmapLinearFilter;", " texture.generateMipmaps = true;", - " texture.anisotropy = 4;", + " texture.anisotropy = anisotropy;", " texture.needsUpdate = true;", - " textures.set(imageTexture, texture);", + " texturesByAnisotropy.set(anisotropy, texture);", " }", " return texture;", "};", "", + "/** @type {Float32Array | null} */", + "let srgbToLinearValues = null;", + "/** @type {WeakMap} */", + "const linearAverageColors = new WeakMap();", + "/**", + " * @param {THREE.Texture} texture", + " * @returns {THREE.Vector3 | null} The average color of the texture, in the", + " * linear color space (like colors read by shaders), or null if the image", + " * can't be read: not loaded yet, or from another domain without CORS.", + " */", + "const getLinearAverageColor = (texture) => {", + " const image = texture.image;", + " if (!image) return null;", + " const cachedColor = linearAverageColors.get(image);", + " if (cachedColor) return cachedColor;", + " const isDrawable =", + " typeof document !== 'undefined' &&", + " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", + " image instanceof HTMLCanvasElement ||", + " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", + " if (!isDrawable) return null;", + " const size = 64;", + " let pixels;", + " try {", + " const canvas = document.createElement('canvas');", + " canvas.width = size;", + " canvas.height = size;", + " const context = canvas.getContext('2d');", + " // Downscaled with filtering, so that all pixels are counted.", + " context.imageSmoothingEnabled = true;", + " context.imageSmoothingQuality = 'high';", + " context.drawImage(image, 0, 0, size, size);", + " pixels = context.getImageData(0, 0, size, size).data;", + " } catch (error) {", + " return null;", + " }", + " if (!srgbToLinearValues) {", + " srgbToLinearValues = new Float32Array(256);", + " for (let value = 0; value < 256; value++) {", + " const srgb = value / 255;", + " srgbToLinearValues[value] = srgb <= 0.04045 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);", + " }", + " }", + " const isSrgb = texture.colorSpace === THREE.SRGBColorSpace;", + " let red = 0;", + " let green = 0;", + " let blue = 0;", + " for (let index = 0; index < pixels.length; index += 4) {", + " red += isSrgb ? srgbToLinearValues[pixels[index]] : pixels[index] / 255;", + " green += isSrgb ? srgbToLinearValues[pixels[index + 1]] : pixels[index + 1] / 255;", + " blue += isSrgb ? srgbToLinearValues[pixels[index + 2]] : pixels[index + 2] / 255;", + " }", + " const count = size * size;", + " const color = new THREE.Vector3(red / count, green / count, blue / count);", + " linearAverageColors.set(image, color);", + " return color;", + "};", + "", "/**", " * A texture of 4 bytes per sample of a grid of `size * size` samples (layer", " * weights, tint and wetness...), interpolated between samples.", @@ -37655,11 +37763,14 @@ " terrainLayerMap1: { value: getWhiteTexture() },", " terrainLayerMap2: { value: getWhiteTexture() },", " terrainLayerMap3: { value: getWhiteTexture() },", + " // Used by the height blending, in the linear color space.", + " terrainLayerAverageColors: {", + " value: [new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1), new THREE.Vector3(1, 1, 1)],", + " },", " terrainLayerNormalMap0: { value: getFlatNormalTexture() },", " terrainLayerNormalMap1: { value: getFlatNormalTexture() },", " terrainLayerNormalMap2: { value: getFlatNormalTexture() },", " terrainLayerNormalMap3: { value: getFlatNormalTexture() },", - " terrainHasNormalMaps: { value: 0 },", " terrainNormalMapStrength: { value: 1 },", " terrainTextureSize: { value: 256 },", " terrainHeightBlending: { value: 0 },", @@ -37668,6 +37779,7 @@ " terrainCliffCosines: { value: new THREE.Vector2() },", " terrainBrush: { value: new THREE.Vector4() },", " terrainColorMap: { value: getWhiteTexture() },", + " terrainNoiseMap: { value: getNoiseTexture() },", " // Z (in the terrain group) under which the ground is wet, fade height, and 1 if it's used.", " terrainWetShore: { value: new THREE.Vector3() },", " // Scene units by 3D world unit.", @@ -37687,8 +37799,12 @@ " ['#include ', '#include \\n' + fragmentShaderNormalCode],", " ], 'Terrain3D');", " };", - " this.material.customProgramCacheKey = () => (this.hasHoles ? 'Terrain3DWithHoles' : 'Terrain3D');", " this.hasHoles = false;", + " /** The defines of the features used by the terrain (see `updateMaterial`), without holes. */", + " this.featureDefines = [];", + " /** All the defines of the shader, separated by semicolons. */", + " this.shaderKey = '';", + " this.material.customProgramCacheKey = () => 'Terrain3D;' + this.shaderKey;", " // Without them, holes would cast shadows.", " this.depthMaterial = this._createHoleDepthMaterial(new THREE.MeshDepthMaterial());", " this.distanceMaterial = this._createHoleDepthMaterial(new THREE.MeshDistanceMaterial());", @@ -37725,11 +37841,28 @@ " setHasHoles(hasHoles) {", " if (hasHoles === this.hasHoles) return;", " this.hasHoles = hasHoles;", + " this._updateShaderDefines();", + " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", + " }", + "", + " /**", + " * Compile the shader only with the features used by the terrain. It is", + " * compiled again only when they change: properties only change in the", + " * editor, holes can be made by actions.", + " */", + " _updateShaderDefines() {", + " const defines = this.hasHoles ? [...this.featureDefines, 'TERRAIN_HOLES'] : this.featureDefines;", + " const shaderKey = defines.join(';');", + " if (shaderKey === this.shaderKey) return;", " // The material has its own defines (STANDARD).", - " if (hasHoles) this.material.defines.TERRAIN_HOLES = '';", - " else delete this.material.defines.TERRAIN_HOLES;", + " for (const name of this.shaderKey ? this.shaderKey.split(';') : []) {", + " delete this.material.defines[name];", + " }", + " for (const name of defines) {", + " this.material.defines[name] = '';", + " }", + " this.shaderKey = shaderKey;", " this.material.needsUpdate = true;", - " for (const chunk of this.chunks) this._setChunkShadowMaterials(chunk.mesh);", " }", "", " /** @param {THREE.Mesh} mesh */", @@ -37961,16 +38094,38 @@ " object._getLayer3NormalMap(),", " object._getLayer4NormalMap(),", " ];", + " const anisotropy = Math.max(parseInt(object._getAnisotropy(), 10) || DEFAULT_ANISOTROPY, 1);", + " const heightBlending = clamp01(object._getHeightBlending());", + " const textureVariation = clamp01(object._getTextureVariation());", + " const featureDefines = [];", " for (let layer = 0; layer < LAYER_COUNT; layer++) {", " this.uniforms.terrainLayerColors.value[layer].set(gdjs.rgbOrHexStringToNumber(colors[layer]));", - " this.uniforms['terrainLayerMap' + layer].value = getLayerTexture(game, textures[layer], false);", - " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true);", + " const layerTexture = getLayerTexture(game, textures[layer], false, anisotropy);", + " this.uniforms['terrainLayerMap' + layer].value = layerTexture;", + " this.uniforms['terrainLayerNormalMap' + layer].value = getLayerTexture(game, normalMaps[layer], true, anisotropy);", + " const averageColor = this.uniforms.terrainLayerAverageColors.value[layer];", + " if (textures[layer]) {", + " featureDefines.push('TERRAIN_LAYER_MAP_' + layer);", + " const linearAverageColor = heightBlending > 0 ? getLinearAverageColor(layerTexture) : null;", + " if (linearAverageColor) {", + " averageColor.copy(linearAverageColor);", + " } else if (heightBlending > 0) {", + " featureDefines.push('TERRAIN_LAYER_MIPMAP_AVERAGE_' + layer);", + " }", + " } else {", + " averageColor.set(1, 1, 1);", + " }", + " if (normalMaps[layer]) featureDefines.push('TERRAIN_LAYER_NORMAL_MAP_' + layer);", " }", - " this.uniforms.terrainHasNormalMaps.value = normalMaps.some((normalMap) => !!normalMap) ? 1 : 0;", + " if (normalMaps.some((normalMap) => !!normalMap)) featureDefines.push('TERRAIN_NORMAL_MAPS');", + " if (heightBlending > 0) featureDefines.push('TERRAIN_HEIGHT_BLENDING');", + " if (textureVariation > 0) featureDefines.push('TERRAIN_TEXTURE_VARIATION');", + " this.featureDefines = featureDefines;", + " this._updateShaderDefines();", " this.uniforms.terrainNormalMapStrength.value = Math.max(object._getNormalMapStrength(), 0);", " this.uniforms.terrainTextureSize.value = Math.max(object._getTextureSize(), 1);", - " this.uniforms.terrainHeightBlending.value = clamp01(object._getHeightBlending());", - " this.uniforms.terrainTextureVariation.value = clamp01(object._getTextureVariation());", + " this.uniforms.terrainHeightBlending.value = heightBlending;", + " this.uniforms.terrainTextureVariation.value = textureVariation;", "", " const cliffLayer = parseInt(object._getCliffLayer(), 10);", " const cliffAngle = gdjs.toRad(object._getCliffAngle());", @@ -38888,40 +39043,21 @@ " return typeof scene.getRenderer3DWorldScale === 'function' ? scene.getRenderer3DWorldScale() : 1;", "};", "", + "/** @type {WeakMap} */", "const averageColors = new WeakMap();", "let white = null;", "/**", " * @param {THREE.Texture} texture", - " * @returns {THREE.Color} The average color of the texture (white when it's not loaded).", + " * @returns {THREE.Color} The average color of the texture (white when it can't be read).", " */", "const getAverageColor = (texture) => {", - " const cachedColor = averageColors.get(texture);", - " if (cachedColor) return cachedColor;", - " const image = texture.image;", - " const isDrawable =", - " typeof document !== 'undefined' &&", - " ((image instanceof HTMLImageElement && image.complete && image.naturalWidth > 0) ||", - " image instanceof HTMLCanvasElement ||", - " (typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap));", - " if (!isDrawable) return white || (white = new THREE.Color(1, 1, 1));", - " const size = 8;", - " const canvas = document.createElement('canvas');", - " canvas.width = size;", - " canvas.height = size;", - " const context = canvas.getContext('2d');", - " context.drawImage(image, 0, 0, size, size);", - " const pixels = context.getImageData(0, 0, size, size).data;", - " let red = 0;", - " let green = 0;", - " let blue = 0;", - " for (let index = 0; index < pixels.length; index += 4) {", - " red += pixels[index];", - " green += pixels[index + 1];", - " blue += pixels[index + 2];", + " const linearAverageColor = getLinearAverageColor(texture);", + " if (!linearAverageColor) return white || (white = new THREE.Color(1, 1, 1));", + " let color = averageColors.get(linearAverageColor);", + " if (!color) {", + " color = new THREE.Color(linearAverageColor.x, linearAverageColor.y, linearAverageColor.z);", + " averageColors.set(linearAverageColor, color);", " }", - " const count = size * size * 255;", - " const color = new THREE.Color().setRGB(red / count, green / count, blue / count, THREE.SRGBColorSpace);", - " averageColors.set(texture, color);", " return color;", "};", "", @@ -42535,6 +42671,37 @@ "group": "Rendering", "name": "ReceiveShadow" }, + { + "value": "4", + "type": "Choice", + "label": "Anisotropic filtering", + "description": "Keeps layer textures sharp where the ground is seen at a low angle (like from a car). Lower is faster on slow graphics cards, but blurs the ground in the distance.", + "group": "Rendering", + "choices": [ + { + "label": "None (fastest)", + "value": "1" + }, + { + "label": "2x", + "value": "2" + }, + { + "label": "4x", + "value": "4" + }, + { + "label": "8x", + "value": "8" + }, + { + "label": "16x (sharpest)", + "value": "16" + } + ], + "advanced": true, + "name": "Anisotropy" + }, { "value": "", "type": "String", @@ -42648,6 +42815,9 @@ }, { "propertyName": "ReceiveShadow" + }, + { + "propertyName": "Anisotropy" } ] }, diff --git a/examples/starting-3d-tank/theme-slots.json b/examples/starting-3d-tank/theme-slots.json index 136d5f06b..741e699fa 100644 --- a/examples/starting-3d-tank/theme-slots.json +++ b/examples/starting-3d-tank/theme-slots.json @@ -2,7 +2,16 @@ "version": 1, "objects": { "scene:Game Scene/Road_3D": "env.road", - "scene:Game Scene/Grass_3D": "env.ground", + "scene:Game Scene/Terrain": { + "Layer1Texture": { + "slot": "terrain.ground", + "normalMap": "Layer1NormalMap" + }, + "Layer2Texture": { + "slot": "terrain.road", + "normalMap": "Layer2NormalMap" + } + }, "scene:Game Scene/Target": "character.enemy", "scene:Game Scene/Bullet": "projectile.player", "scene:Game Scene/Walls_3D": "env.wall", @@ -12,5 +21,10 @@ }, "effects": { "effect:Game Scene//SkyBox": "sky.day" - } + }, + "ignoredObjects": [ + "object:Terrain3D::Terrain3D/AreaPlaceholder", + "object:Terrain3D::TerrainGrass/AreaPlaceholder", + "object:Terrain3D::ScatteredModels/AreaPlaceholder" + ] } diff --git a/examples/starting-expanded-3D-platformer/starting-expanded-3D-platformer.json b/examples/starting-expanded-3D-platformer/starting-expanded-3D-platformer.json index 9a72a2bb8..23f2ced35 100644 --- a/examples/starting-expanded-3D-platformer/starting-expanded-3D-platformer.json +++ b/examples/starting-expanded-3D-platformer/starting-expanded-3D-platformer.json @@ -2957,6 +2957,51 @@ "source": "", "type": "BuiltinCommonInstructions::Group", "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Start with touch controls on touchscreens." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SceneJustBegins" + }, + "parameters": [ + "" + ] + }, + { + "type": { + "value": "SystemInfo::HasTouchScreen" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SpriteToggleSwitch::SpriteToggleSwitch::SetChecked" + }, + "parameters": [ + "ControlsToggle", + "yes", + "" + ] + } + ] + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -3503,18 +3548,11 @@ "conditions": [ { "type": { - "value": "MouseButtonFromTextPressed" + "value": "HasAnyTouchOrMouseStarted" }, "parameters": [ - "", - "\"Left\"" + "" ] - }, - { - "type": { - "value": "BuiltinCommonInstructions::Once" - }, - "parameters": [] } ], "actions": [], @@ -3533,17 +3571,6 @@ "\"Left\"", "" ] - }, - { - "type": { - "inverted": true, - "value": "SpriteMultitouchJoystick::MultitouchButton::IsPressed" - }, - "parameters": [ - "JumpButton", - "MultitouchButton", - "" - ] } ], "actions": [ @@ -17328,7 +17355,7 @@ "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", - "version": "0.3.1", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -17376,7 +17403,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -17624,16 +17651,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -17816,6 +17873,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -18122,6 +18204,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -18143,7 +18237,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { diff --git a/examples/starting-expanded-3d-grand-theft-auto/starting-expanded-3d-grand-theft-auto.json b/examples/starting-expanded-3d-grand-theft-auto/starting-expanded-3d-grand-theft-auto.json index 6181db416..b1838de62 100644 --- a/examples/starting-expanded-3d-grand-theft-auto/starting-expanded-3d-grand-theft-auto.json +++ b/examples/starting-expanded-3d-grand-theft-auto/starting-expanded-3d-grand-theft-auto.json @@ -4719,6 +4719,51 @@ "source": "", "type": "BuiltinCommonInstructions::Group", "events": [ + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Start with touch controls on touchscreens." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "SceneJustBegins" + }, + "parameters": [ + "" + ] + }, + { + "type": { + "value": "SystemInfo::HasTouchScreen" + }, + "parameters": [ + "" + ] + } + ], + "actions": [ + { + "type": { + "value": "SpriteToggleSwitch::SpriteToggleSwitch::SetChecked" + }, + "parameters": [ + "ControlsToggle", + "yes", + "" + ] + } + ] + }, { "folded": false, "type": "BuiltinCommonInstructions::Standard", @@ -5950,18 +5995,11 @@ "conditions": [ { "type": { - "value": "MouseButtonFromTextPressed" + "value": "HasAnyTouchOrMouseStarted" }, "parameters": [ - "", - "\"Left\"" + "" ] - }, - { - "type": { - "value": "BuiltinCommonInstructions::Once" - }, - "parameters": [] } ], "actions": [], @@ -5982,17 +6020,6 @@ "" ] }, - { - "type": { - "inverted": true, - "value": "SpriteMultitouchJoystick::MultitouchButton::IsPressed" - }, - "parameters": [ - "JumpButton", - "MultitouchButton", - "" - ] - }, { "type": { "inverted": true, @@ -22040,7 +22067,6 @@ { "author": "PANDAKO-GitHub", "category": "Input", - "dimension": "", "extensionNamespace": "", "fullName": "Mouse Pointer Lock", "gdevelopVersion": ">=5.5.222", @@ -22049,7 +22075,7 @@ "name": "MousePointerLock", "previewIconUrl": "https://resources.gdevelop-app.com/assets/Icons/Line Hero Pack/Master/SVG/Virtual Reality/Virtual Reality_360_rotate_vr_movement.svg", "shortDescription": "Lock and hide mouse pointer for unlimited movement (e.g., FPS mouse look).", - "version": "0.3.1", + "version": "0.3.2", "description": [ "This behavior removes the limit on the distance the mouse can move and hides the cursor.", "", @@ -22097,7 +22123,7 @@ { "name": "TouchSpeedFactor", "type": "number", - "value": 4 + "value": 2 } ], "eventsFunctions": [ @@ -22345,16 +22371,46 @@ ] }, { - "type": "BuiltinCommonInstructions::JsCode", - "inlineCode": [ - "const { handler } = gdjs._MousePointerLockExtension;\r", - "\r", - "handler.requestPointerLock();\r", - "" + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Fingers are followed instead of locking the pointer, because mobile browsers give tiny pointer movements." + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + "<", + "2" + ] + } ], - "parameterObjects": "", - "useStrict": true, - "eventsSheetExpanded": false + "actions": [], + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const { handler } = gdjs._MousePointerLockExtension;\r", + "\r", + "handler.requestPointerLock();\r", + "" + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ] } ], "parameters": [], @@ -22537,6 +22593,31 @@ ] } ] + }, + { + "type": "BuiltinCommonInstructions::Standard", + "conditions": [ + { + "type": { + "value": "NumberVariable" + }, + "parameters": [ + "TouchId", + ">=", + "2" + ] + } + ], + "actions": [ + { + "type": { + "value": "SetReturnBoolean" + }, + "parameters": [ + "True" + ] + } + ] } ], "parameters": [], @@ -22818,68 +22899,12 @@ "objectGroups": [] } ], - "eventsFunctionsFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "functionName": "onFirstSceneLoaded" - }, - { - "functionName": "onScenePostEvents" - }, - { - "functionName": "RequestPointerLock" - }, - { - "functionName": "ExitPointerLock" - }, - { - "functionName": "isPointerLocked" - }, - { - "functionName": "isPointerActuallyLocked" - }, - { - "functionName": "isEmulatingPointerLock" - }, - { - "functionName": "IsMoving" - }, - { - "functionName": "MovementX" - }, - { - "functionName": "SetMovementX" - }, - { - "functionName": "MovementY" - }, - { - "functionName": "SetMovementY" - }, - { - "functionName": "TouchX" - }, - { - "functionName": "TouchY" - }, - { - "functionName": "TouchSpeedFactor" - }, - { - "functionName": "SetTouchSpeedFactor" - } - ] - }, "eventsBasedBehaviors": [ { "description": "Control camera rotations with a mouse.", "fullName": "First person camera mouse mapper", - "helpPath": "", - "iconUrl": "", "name": "FirstPersonPointerMapper", "objectType": "", - "previewIconUrl": "", "eventsFunctions": [ { "fullName": "", @@ -22899,6 +22924,18 @@ }, "comment": "TODO It's probably a bad idea to rotate the object around Y." }, + { + "type": "BuiltinCommonInstructions::Comment", + "color": { + "b": 109, + "g": 230, + "r": 255, + "textB": 0, + "textG": 0, + "textR": 0 + }, + "comment": "Both rotations are relative to the screen height because the field of view is vertical. This way, the speed doesn't change with the screen ratio." + }, { "type": "BuiltinCommonInstructions::Standard", "conditions": [ @@ -22920,7 +22957,7 @@ "parameters": [ "Object", "+", - "MousePointerLock::MovementX() * HorizontalSpeed / SceneWindowWidth()" + "MousePointerLock::MovementX() * HorizontalSpeed / (SceneWindowHeight() * 16 / 9)" ] }, { @@ -23154,7 +23191,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "HorizontalSpeed", - "group": "First person camera mouse mapper configuration", "name": "SetHorizontalSpeed", "sentence": "", "events": [ @@ -23235,7 +23271,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalSpeed", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalSpeed", "sentence": "", "events": [ @@ -23316,7 +23351,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMin", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMin", "sentence": "", "events": [ @@ -23397,7 +23431,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "VerticalAngleMax", - "group": "First person camera mouse mapper configuration", "name": "SetVerticalAngleMax", "sentence": "", "events": [ @@ -23478,7 +23511,6 @@ "fullName": "", "functionType": "ActionWithOperator", "getterName": "OffsetZ", - "group": "First person camera mouse mapper configuration", "name": "SetOffsetZ", "sentence": "", "events": [ @@ -23515,57 +23547,6 @@ "objectGroups": [] } ], - "eventsFunctionsFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "functionName": "doStepPreEvents" - }, - { - "folderName": "Layers and cameras", - "children": [ - { - "functionName": "LookFromObjectEyes" - } - ] - }, - { - "folderName": "First person camera mouse mapper configuration", - "children": [ - { - "functionName": "HorizontalSpeed" - }, - { - "functionName": "SetHorizontalSpeed" - }, - { - "functionName": "VerticalSpeed" - }, - { - "functionName": "SetVerticalSpeed" - }, - { - "functionName": "VerticalAngleMin" - }, - { - "functionName": "SetVerticalAngleMin" - }, - { - "functionName": "VerticalAngleMax" - }, - { - "functionName": "SetVerticalAngleMax" - }, - { - "functionName": "OffsetZ" - }, - { - "functionName": "SetOffsetZ" - } - ] - } - ] - }, "propertyDescriptors": [ { "value": "", @@ -23619,32 +23600,7 @@ "name": "ShouldLock" } ], - "propertiesFolderStructure": { - "folderName": "__ROOT", - "children": [ - { - "propertyName": "Object3D" - }, - { - "propertyName": "HorizontalSpeed" - }, - { - "propertyName": "VerticalSpeed" - }, - { - "propertyName": "VerticalAngleMin" - }, - { - "propertyName": "VerticalAngleMax" - }, - { - "propertyName": "OffsetZ" - }, - { - "propertyName": "ShouldLock" - } - ] - } + "sharedPropertyDescriptors": [] } ], "eventsBasedObjects": [] diff --git a/examples/starting-expanded-3d-house-horror/README.md b/examples/starting-expanded-3d-house-horror/README.md new file mode 100644 index 000000000..ceb8c3324 --- /dev/null +++ b/examples/starting-expanded-3d-house-horror/README.md @@ -0,0 +1,3 @@ +# 3D Horror House Escape Expanded + +A 3D physics-based first-person horror escape game in a dark, furnished two-story house made of 3D boxes: a living room, a kitchen, a study and a storage room with pushable crates downstairs, bedrooms and a dressing room upstairs, linked by a staircase, and a fenced yard outside. The rooms have old semi-realistic furniture (beds, sofa, cupboards, a grandfather clock, oil lamps). The player only sees what the flashlight lights, and must find the key hidden in the house to unlock the front door, then escape through the gate of the yard. A monster roams both floors using navmesh pathfinding, climbing the stairs and finding its way through the rooms; it uses raycasting to check if the player is in its line of sight, then chases them, and the game resets if it catches the player. The player cannot fight back. It suits haunted house, escape and hide-and-seek horror games. The game supports both keyboard/mouse controls and mobile touch controls. diff --git a/examples/starting-expanded-3d-house-horror/assets/Classic Nightstand 01.glb b/examples/starting-expanded-3d-house-horror/assets/Classic Nightstand 01.glb new file mode 100644 index 0000000000000000000000000000000000000000..9a0f4f1f92bed042766f91c9272161d9b6986fde GIT binary patch literal 376928 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
  • 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

    q53b(59J?OIv2&6a&f1$%@#VuA`9caxk>D$d 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

    GQSmn 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

    gx}?+O(>4WXWMiV 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

    H(2Ex>cGxS+vRJw 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 z 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 literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Bottom.png b/examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..5c13b34da3c7bf5e9b03cac95d9f51c25c87dda1 GIT binary patch literal 76396 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�v5aewtjA~{3)5XBu;~0VtpVcm9`EU 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 literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Left.png b/examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Left.png new file mode 100644 index 0000000000000000000000000000000000000000..4141f54d337681ef13b2b0cc1ac108dd90c030bd GIT binary patch literal 109309 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%0AP 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 literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Right.png b/examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Right.png new file mode 100644 index 0000000000000000000000000000000000000000..a5bd2e80c5ec12dfcf5ae7fe730ff1269e2accdf GIT binary patch literal 145006 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 z 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%0DheX_Vm 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 literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Top.png b/examples/starting-expanded-3d-house-horror/assets/DarkSkybox_Top.png new file mode 100644 index 0000000000000000000000000000000000000000..81cc3397b8270bb2f52fe7260899797b06efc80d GIT binary patch literal 141982 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

    `NBUa@~k2_*}kPXkmQKfC^cab6gQ?fBD)YT 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

    v2%ZwxeO9*Y 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 z =`;&Hm@nmhcKS|?}YJZZ(^VR+&jj!hFQ`_xNx)I!1?N8G9*5Z%XcKegE!#&jg zB#oaR)~B}HpQN!qv##->Sv`zC_75ei{Ye^!t267_;f-p4(lE6@sewAbuJJInKS|@V z>il|x#p&nQkE#7h<<$9gjmxY3Ng98r_9toFN9|A2xQE)GlpXG`_9tnq&#Y_QUF}cO zc&plOJm@k1tf=hvHFp6s1p*Em_7U)MOhGwWLZnA)GD z@k45VlEw?v{v?e@tNlqDFHrlFG(P%$`u-%17pnb9fBXLV{QAGdj@zH4&#!M&=hrp< z&gx@-lExpY^Xu8+ht>WhjmN0{NgCHw`;#=*XVx{Iq4pB zGM#KWmI@>U@#U6%DRt~+n%yPI<3kd9%ldZ`HLZMw+RjR%1p_Zr_a5Use(dhc^iEt7 z6)$(0zUwlMa^H5DM#YS$WyLR3TJs6?ai7c7H*UPg%UtTs)Oak7`1x` z)?$LkLvMYYs|-)1?MMEmq}U0xy~|~4Uwfj*k$>^^F;xHSziCnUL~7pSGCf^xlE;S@ zxlF0GCQ_TCmuXk|NwlW?W$KfEGEvRTl<@OpTJh9nnwl$}7unXEU##w<&~N{ye!ov5 z8hx3*`9bt8NBh^+9!nc*QD;FDDM2<6t#2;HD7<3RxX(8 z@%P$De||oN+B_@#^{KRZ`eiztFpX|sCH>ZZI+f)hE+gmCzuhZ-518ihHy-W9AO1Fy z?y7QycGa6kw_dzVNe@q_)un@Yjp%1iuf8jYo3$N7j^FW1PvaNnLFGTEnR(Fq>oN3F zfvZ%ck*>7ty`Aa*5HDJ2;N3j$KBd%!%WYUoWRWzmDVfCzsKRqjK(i`7)|L zGmbxedKn#gBaUDBXc>L+K^$-By^Ma_F6YU8%V_TeNx#38UVJx>Uwn5d%}JE&4S|j-j0wV>#;dVrtyIH&3seWYSGqFC@&XgGc3j^S-|+ zqVy!H|3q&d`lQU)Ut{^r;Dz-4>v25j{rQCPp8We*s+{`@)txwwO1A6GS6)e?4j)Uq z*3GB5q&VJ|Zy{}79mj8euz+%|6~C)4q)N$hPQJuKdi_&rZ^{B%F74c(YatcO70nS^DdG0s9I+#bYI8gv7W+rO>&3%=O`=6zXZ2 zTs~wWUG(?jcYaHvp#`r}i!b}p)=j-Qx#~C?Qt2ukOdCL$4@mcueK8k@4Dk4@u&eaP z>w^g6jr;qY*jvH+6FMcv5iSCwktn^pi+P!#cY$COr5YM?~|6tX)cutF1NL}OO zxyF_Sv}{~FC*@yAU3}u#`lYnELp*m_x0F5>z1rKBQU5{lJn@-j6cPFu@0IcJf7_G$ zz2&1`edGBn8TSf#9^>E%%P49`PYwz8(Y<$Gr2%q&y>pwM=Kk6$e)cRmn%dvq(~MK~ z=2z)r!bs|Nr3e2e_w$CPLEJBTw8v|-58|GyMv~)m>jiNMpN|~B<0*-IPmHF)gXR9& zFp@rs4dRkhe6;1kAWn`RLp^;#+#)1_#!m|3_=w>Y94GssejnlS@!f+ss`hYle91#s z>FKXW7=I9d=C;2|c`FS!{vuxeEcrFN3^nb+{D~9)_f8pN?jyv~|$E(edeP`W=(%zXte08`pyBE@avD@{{WoBL?F8wX{PiViXB(D{++i#@zBx#(TzE5n)<-2))-LBW( z+@BOU*DmYI|G(`|@?oB1vdezHfA{>lD{Jl*{C9JIlJtV~=l_uXNj_;SUcC!91onUG z{JN>j?v?RlZ>8SzadUstwco>`_Z#W)`fqf8{hIUWcCU{)<8IHR|9^LW{kClt{h(?& zkN%(7pA@9duLr5~>%RX^=hts!O-Soxwoe;bhpF@H8tXM7jrIDFKEIyb`Vi`J>q8o&E_Z%iW3qFQ7eq+5Rq_JKT(pawvX{^_TG}dcE z8tXM7jc=|G1-{=H>mTmBj`f<5#y8i80^fCfbA2fA{pWg3NaGt>A9{RK7#H069M65Z zA&=U$k}{{u|EnICzVI9u*%QU1o>@s_R<_~|Pk$4+dRrJj{K!yte8uT7KKAi*TzzXp z-oJ4rHD1z?k8gU-<7Ljb;u#zFM?Udg6jz+`8jV=nkk@>?!sB=EYRDZwdX0L2+mM&+ zTR|s(Xvn7yEvEwK8ghq2%V_(ihTQk7riCyuTi{Uy{soly`A?j^Y{-X z+nD?-m!tT+yq7+r{Vh%UGE5v@iMINu!uPs-7?u*F!zen+$PK)T&?1o&j+d_};mHsJs?;`4v z+>nDiE~Lq?H{=cD7towH!+3X_k-TqyL$i)>=Y)n_cg6y89Q6hj+Z}o7SQH=Jx_~-N z2;;n>|MhbX+4t`JYtpS=4&yUN6WDRIYfse9NX&zN6-RPmnFqb|ETFN!*5iA&CGecD z+wdP3wnd%{760Gf8Tq`t|D9F-U3x>-e|A@Tm*{vKJ~?AYWU|O7mRLuxS82m6LJ5@5{&_S?_rA_Vx63nbzEC+_#Zf59zycBh8ieV4il)*^pP9TS6Nz zw_;z;{gJ(89j0}=6sjkB`Ew>yrZK7|MS_cIBMKik)37TYI;aAt&nxA zPsP8Q(^~POq5C3d{8o=&?>m$S4{BxR-I0(me(U5=PKs$|=2^AR!npIkq3rleg~Rw@ z*I_2V>jR%fPLlPri^&`5?PaaF#ge@yeYVtks`W-|o-y*%$T(SlJ1PA;R@Mc6TfLFW z%6iz4za=f}Vbi7E3uV2oQ@i)5yR6qG%6R*U?H@ulp|iJ(}6Q z4IjO2S7cfa@qg?(nkVan58U@IefoAAE`Ml8BnOA_fu0FGKH2TQ-zLM^@wt-z`IBMnc>Un|d|L895PwFBJXrYRM}~39%VGTX7ehHj{CT6p zFpt0eOBk00djxUm-U|0Yt~VstpEJc z{yo|w_v?zu>*#{;A(HmXe9XUnBlVE=qYouLP}Y;Si2fY8KQ}DhNathaewKN#|Crd3 z^pmJh=Jk%Z;&_qF_mdlCd}aP`7km9;*Ae0!=2?le@?4p`@aFoEd^aV&mr~v}v3uX7 z-ves7oU1eMQ}KP3ID?((+@5*&s^vG=hiim$#O}s%)Zq;VH@e(0+Deq)kxbo=GsT{parJ3plHCUt&DF0+=R7|YnzTfz-uhPHY_~k=m>bUPWF6s~H;QNg=zGU^y?_Vmssbc!? zUuK8@KAisj#v0$D&JStaS)Cu!xQjYJq%o=ULmKip0cb$+OkoQZMqu)I1yG((*q>ZiWnSmPP${E)^))cGNeqty8! zjiKYt4{3}(ap#9Lh7a!hjWtG}xbs6Aqh0R&5cA!zjs8Ra&8yARA|NYCu6^GSv=ZEf?Ezcu+e&~)@$JBA( zZ~SW)_4}7i)6Wm(zL5U=mpK!MdB1;o>1_J%U;aHK{r4|NZchLGOO1E!9$LqpA6lr+ z4{5yXj~(WBFCV%;m`i>!gsw^7x1G*C+K&$0l9QuGK1Tza#&G|?tMHy&J897G{mJoL zAKOVQQ=g?SA;H}5$Pn6pukb>{JRbUd41e`*6%Gx`$wLPZqgqvhId7>E9v>ML%$0Kw zql=ev@XA|8(8b^7dq)e7q#eSO&X1D)?ZMo&@JNprI2^;3f4!5hd>_nHc_h7bM=+oK zMb58Sj{Jht?&SLp2XocX(R824W4ro1UTSL$`>Ni_OTG=}5|8_6h1g%)c#OyQ{h5Os zb@S0*;!lUBaxURY4xU{jk$%Y+%uQ|?OP`AWsdp!O9Q~4(RGEGIgSlCmL@IY*Fb^#- z*5hq|>csD~tITze1oM;U6De*|6RV16z$q2^C0)QL^BUI+%cXS zcHB;ByT(v_3HiR^Pb+g!U-`b&mn-ucouQM~kO2(R58#izau;e=14xLNL8T=Hro zu2i%W7u-{s`%TNmUu}uv{qs9<-wAhe^O?Cg>79l=p-&7qnpB04OZs4r#*BH2_Kf}} zn8!C7L#>9!aQ)Y-aKe!gzU7m~Tv7C1tZkdsTadleyYNCT83}~v7eMThAR}li$5QflS|#z zm_Mo-!X*BkJ0bI^Wx+?em&-H99KxQmg_DQlk7^N9URck2XwH|^dKKKxfB zj?EduGo_vHRuAFj((VWHgzzaDk8`y{c!`Y1>0%*VV?Y!Sy(ff^%Q*HJmXq6WjpDC| zM{}3Pck+Y2ocxiD`{a^hSLT85k!Y@bu`-|Ox1HkijiGk(eaX0A_a<$pnvLZ=(e{q! z{(gO?#HZ7vOd9bZ_r4v}pqGyvZ*+PG)h8#azdMAC?*GDzOcG4f! zMpLKDJLt)XF?99F4tgbTBK_4|;@p6d^lPV`)MEVzY8JGUPCq`<P2L`?v5H^W)n^+bLuVIAy3USmodpm{PF283f_bJBd^AbBL z;@B{9e3SSWpK~ZVUby#8+AF`y8`O6vHOW1cD)ie)8;T8~vQLYj1qadgQakD3Ekith zxcg4(BfmpDE;@u?miwt!!w_yR_sgi}Asj9D&)r=^I8VnY{<2pHzm^cixx0k$02!~2 zGXG{j8O6^CZy@RO!u#iydHh-kca!wdMIk&_^mohs`RQ+sxWfJreqZK6k!~^{Bt5TV z2)`urI_SO-t|{}qbo~&1Q0D(bVrP2$D8@WPy!-21Fc+JabaQ>kzE_gp)533E`ZNFj zrI!B>T_3{xZ1=mK=6gHkT^#moo8Nnref0kmfB(|-3Dz2Jo*()z{ryXH@&9kXe~G#C z-}3yB{!Kx2ypUYxTvz7bzclij-)|gP|F+++YvQ3kZ=~0I?3pd|z3%$Ei*;G8uXX+} zf4{LA>;G=wZ>;C4?Zf}d^&#K?3+IOl$Ve3u$|(d4omRht5B#=aiJ0xgNFz$JogLL9o;Ww@CO@GuZNR=Ne*{9 z+2LAZC;7QN;johxey?46UDv}Ywl3&ohhcxC)CHaF@Fuad!Rlm%;b*Goz)p5}<=mzm z)^G`(tJ0Ku<}5)veQ|OzBL|&g=9mm_f+r-#=V^%X$ z4r$nN9D1%CIOMPgeV5++OgrT$iXir#Tq^2SFM!a=+AlcZljO%@1p~D9N)Y&VDFaBvd2>FBMm!_L(i21 zhaC2x@6vhiyw~W1!w=2j5A+aQ5d#rhfx%tO1%JxQ!4ZQIn-N!W0pki0aW_X^!%F*s~h6sjVGwg7{p zjgTQ-*<$djLU#$>EmYlN@bW_F1LQdjj=p$6sG1PU0)xXAY}_MM!(wpQf{*tJ)v*{H zzCt%#sHVl>C<9%55A6LGgQHA6A@l{>4h&vfsJ=}*3|?0VKEl5+i@_TRMF>SH3>oqw zguYas+S=s^bVsNwpvIm8lS`3c7hC*$GT38I; zObC60Jcq&2N6_si)Y4*bl!5J5LTxPuM;##Gc9ut5{D^R1hY968XU3E+2A~=^+#^)ZSw74npVy zNbb!H8W`X>TkuafJSjw-% zQZwT_dcPF@XQe?#uJMu|3M3DH=P@JKcz?shG=qBiEyklkil*c!IYxEsP8(rDV*p-D` zGsHb<>iqDGTbi-=s0h zK05J{@Tgnsn)W&jowz3F8oYW>C!_B$d~0v@GvgSm54py!UdT1h_u=CD+-0z7m&Ut4 zc`>E~Qcr9h+fv zG%hk~O3I@vXBxS~@F6?w>_aCzT-Evs9gSUEAlGfz*!cz>hY=GN_s^Nq?otyI9~_3x z%GV}`zj5gib6;zm|D7J;^A^@Ia);5M&{-w=nQ}GLo-%TW;hWRRjG=Q_^dZ;ym0B}X-Wz>k1LPXRhf?AXa1D$tkKU7r}k)@@~5@wFzj@`=e;^_N!jb+ z>Eh4tQWiQIZxoxCtXyNXeS`D^^c~(hBp1IjvpN5;r7*uzv?;fIHYe|>(wukRTZBhd zY|6;5-KRO{e5Wwat{+H$`f+m(UsISn9%{m=e-`4kk34AhlEBV_o}s+E(Sv+<`+%Kq zP8Q;I_XP4`r^xq(_~L{>8g?GoQHbXqviVh7@JmmHa<^fD@}J2$z&!&(Irry*^yc@P z8~-5RT(=0H{HcjaLw+f|2sfG4B;c>u>H0!pUOgd@|74RE{C3kKd^T4gy)yVgKH9Pf zZ;?G4Xy2u`TJVdL3v-bxjd^@RD93kcY5YgI_s4|t#ImhS8s#4Upb$5ByrpR`$~F41 z5Ra04?4@ba`$4XfR*2s@8%R&D*V5RB{F!NmdAF?(@`ooB<~c(enfznHt+>W>h56JQ z4NZHR9e$8IHz~rAPd75@h<97^!a7CxoP3`_oe`m2=+A&Z&>Q?@D93)%+V}^(Tx$w( z*Nv@>Kd_tdNGN|dtc}TU*{v1t2@mB4L2XTX-H)w!$;*W}txFrDzj;+FQy=tRD^r9Y z|0&9(q4!rv5iTNoRnTA1`=o1Oo|3DfNsqa&H7|LvFn^I4$p6<%t=Zq8Fi$8edtZEo zc<6Tl`-!4=WM*NWTOeR}ZTr@I`b=S7az%dEUgq7hBdv|S+!fmJFJlXvJyoc0(V^D- zpxAHzbwKaxtF8HiZH4)b&CIj^F2oC#1=<7ow&X%w_pLx0_AoB6_d(@Qeyw*vj(XqQ zCG$3>Ex**i5N~bX*66|Sa^i2!>47xry|SecPstycpGWR*&Q)SUd2R8)d~EuAGw$Cw zlyCo`h3U_2A2u`Xfc)W#MfjC=f%^&ac?FAbtx@*=n$nC7cyLx!DtidE(GOy5fOmyr5lS&b6Q^mtItex14Ta{Dt1Y35B@n_COkXDV0JwZGFI> z9a2x>TjYM497qq0YsT&F4CQuR1L-;U2Kx1)?EYsLEb&I2tPlz z84uhi@#BR+{;Z-+joqBjH06h<7UI-3fqGI>0_Bj8`Gouh3kvg^F9Yp^-QGVH=7+Zg z+6Vm+j~3?X?+4QG6Z3gg|7I*7eS(Vg9qlhRcVeV`LN#d-`9Swg8pTI8?9VI@`gK99 z|A$(+{F(HF#_jIouXA}XDLKrDp0Ot^LtR>~>vD1*^i^GudzY%q$$iM&oaZ_JFVW-S zgOi&wkN!BCU+DLBgpwQmx2}%n@^`mNfs)c;Q^@|8u9KmEbX`v0hawLh8_oY(b17Bo z(sJJ|wMH{9Sh7jUO%3zE9_0_8z9myXXY^m$)a}wXwLD1K%pl)aY_xyrEo)GhlN+Bu z+C0)9-ZhW(TTqbFVdJ3vFI~rLm&uvEbcDZC-3T}CJ`oyP^ub6T)+|q2ruO>2dTRu~ zcyG9qTm20F_*7Z#r!K4ILCOaw7dL`@jqe`DJxf1@x-!TswjRQ57EZ}54|=7dm{O9P)j)QG)d-8^5SM@;^cxvZI{8B)BhMKG3`T4ac8S~ zcT)bZ>B9KY1M}RNM_<alB? zEySh0{1#SSm-%^zT?OwhZ+=@V_4=gw*VGaxrZBVF{PZdL4liAMobQ~x`1IHAb^WR@ z$P5Xajou7E(jcXb*>%PB-z4H1j_-8|Ab>nuvdqZ6E z^X9R&d2^cD5NE5zQ)lZl{VE%H7a=Y^^JdG7|NgdB?)ceGm*nsJTVL09+DJ#O$-(ze zwm*LQVo=Xv_{E$qPahe|`pyx3GUZ2Z*PfTjH~kao+zi?K(Xw2hY&^|^IeX}nzDnY4 z1ziMi?A4xQ`TdJgo)9Qi3ASu{<3GNkOsa*mi>Ug1LqhV~t#D-sd?s z7SOwc;5yH->~W2tRM5(EY-d3y?+1?UD&VZ|7hLN(mNOH(UhqNBv8;VaKrd?H*bfML zc|UM$Hvv8R3%YxbrB_cuZvkh4V>uf!{2M&S_7(IId{}Uk=hz+s?trzxvE0RA!HoiH z;aGanqo3er&$0Ak#sPwXo@1Gn+~I;U&#}~y`w_vdo@1#QBH%7KI~;q9;G^CT96LzB zjLgRe9*!L*kU#RoNW+P-cAJ1+)WWf&1S191$RDP1>_h<{Z1Tu~W5)=Xy+SbBb1Y{d zHeN8+b1ZAO3nmH1d5$d?a5t<4j^&QXy+csxIhGoFPY_gjj%AO@0_MHb1I`)l5`4nP zSPQX_`&hNN`EVFjkB|k*;&W3#*EDOHP5k)g0Bl6G@KY~ zn*{7ZPdIj`fEgbWZ1x<>tn}C_cv!&tBZBRoW65JLa>!-~3SaC!#)FmQgaeL{L>^+V6;GsE{Ug$CHTt3Dw;KJ>@=iuSw7htCPCpEsGltqi9%_kOUh4Z0xBOM3A6h=n=!b!G z_7g@wwA|(dj%Ibj=!b#Rr<2hS11J9vqjUOU;LP07=!cfS?DNU7JnTi>@{(T|{m}5L z7jycdwYYTa$??c>jTWfiDqaRwn+vtauzvOj7&K2?tdB`VjxviaVv^&c; zc#V1KeYU0|D1jpIQMYg=NIx*KA*VdFBtvM^1entw7l!qoPHQM=M6c9oSdK^T7JOj zhn6!#&<`zNX7oeLCm8)OaL!0h&<_J=wu37lHu_=9{2iko22RhJ{T?y;Vat4y(GM+u z+vtaubM~Mg2EKfDYu9gRg`2c3QvL8$W#fnySCzQ3lBDW~tUuen!Y$kwseXt*Ye|J` zULUD`cu%)j^~0^JFZLO_K34s3TYRz4(kNE_kaha(E{Rn?#HY`TqNAW6>iY8)Za`zK z`XTlA4=r&Ew#2F*;xBG2am+`&Pn=Z!5TAH$m!#^4IWAcSs2=CuniHvh*kebm`XT#KH~BlU>WBE$U3e{}`XTdD_sSX36+}P8 zKPEa;=5$K+L;N1EjCb@WessR*CZZqW6W?DOseXuG_e7=Jd{?CUA@jYtztla~J*oO3 z{$Dn>cSWhB>W7D$V$~0shrHybSoK4E@*e+PO7%nbr*G#KvFeAczdby13u#@d6ZC$`i{6S}+-8oYIuzYc(dSQoMDb*3#hy0s2r&PDYCx7DKQ>y1pA0MmE$9y&Yldk5EDb)k< zs}Ce~&MnVXx&1p+s`F8Q%bF@zCVE|y=!oP!wLGck!1is9RA=NI)H5ITQ)fl0PZDRJ zDTgA}Fy3e#n0G-83&!{Sg1bC(GTQF_G$r_&;bUcWrKpR6qRD zFH@=?G7ovtlPT2?@yWY;T&(&b^RUl%hsfWP=!f_{2N%1ua=++@_!Y$$=Ow=5=}7fM z<|BSu?gRZ0f6xnU-8#|z(GQvDhvnt&T(?N|L;Sh#j&<*LiBvy)M|3&#L*^l`_12W? zhxp|2-q8>7XMAt0Yn&6Se#kuRb7VoR`XTuml{C^K?tMd>)^yf(R!{}e~ z{UQ1x>!bf#q@5IIR zb0;4IAZrXTv@UcX|4|E**!k?9Ib1pi`6YN2vxCIw63~2#={od ztcp2hbIU5q<@S_URL(4(VJmRZe%CeD*3~e_*}6+aS}nJ>s)jB#MWU%~t8QMjC>)(v z7hWz^Y9b9wBaPw4*xZ#%>F#(OPH(QQCeqwUec*BtZm3#8H_4e7aC_`tr{CxCxqV*0 z-Iwdgv-`bHx7`_V&@Q+=0p1BO%%q{1P4uVdID~T z*WkCVt&+I?ts_XT22O&Q*xQk zcQ~B>wu}4ivKnoD7dK_97^4u)eZUcLQX3sO6_{97jt^TV>?oS;*mmE_jlquaq3)N3 z6vqm)&R458CX|jD=D8|whNtXuNI#E}pN=rkRU9kKem)^TO2-WIT$MM&J$l`f;QV={ z(-G#i6vqtrGjtZL+8FEz^IXL-!@(~DJN8d~v2fS=KEaOg0piTu&?mthE4=@bsjWH| z_#ow#jum!1d~QhjvBECmC><-j!ZkLnV}(}{N9mYh>b)Y~H|jC&XG_fYRB@~@>rl^g zKT91m%yU)V443Y5$hp*G!HzJ`RU9kKeyHaYO2-WIT$MM&)O$hBQ;#J&!ba~&jv1zB zLF!P?2Rp(%S8>d6uw+6J_w(!x)Xx^!=ez9z=6oHQ8MMMYm;3z5_0;ngnC3bSorD#Z z9;oNjeoV0RK>4(vPB3fov!lG3Vd*EOlk(OHW=($9lut9vJ~^*^nqk)A=TUhx!|ctN zE4`Uv*5PMX`7y)nhx5u$XP7nl8CTxSFncp}q_@uS^t(pOef#wJp}|b>wjW0pEnR&^ zXv2{)!A$TsU582i1tUDcOz`YS2TFdgsl~yLu#@gl<>cZ7bIdTW#rdXTodsK_}aPkPP-v*(p`ua*DK@cQ{S*&FQN3bRk{8Rgjwvo{C% z>`D8d31*+%V`m!ow=>M%m~$ufj}>O0%uzjQhPO1YD}0~cZ?pD}2xfxEU_s#(rCSTV zJ@SKA_=A&2NX=ov!eA!&L*n!M^X&YX!U}UOthx2|5s6GNue;`n zRcQ~MVP5wDy-Sq`GtBF9UU@LXygwJxx@xaF!@TGG`^snRzZsVG5@)t?Pnpvmzq{@F zB)@NKb`B0&;ls~fE;-E~WCwNJ_05Z9{^IWWK`ZQep&@zCBNd_Rasojsyx`z`sdLxN zl3=Eo-$k>_OA^fQ4D-61$wOUkAYp~sKkKaRk)N=_Tsw2FJ&>KyG4C6{yEg6`oUp>| z^We*QY0sTu_Q~%k<=G6gPtGgPW|(~r|IC~AY=+r0zq^$G&akRQ-7l`CBh0n%JLejs z2h1?n!g`ZC&zv}2muD*-y37Z!(|#?L*LCz<8xOpWyhtG~QR~{ugU(?Zt*N*?Lwab( zQF+~itVv!lGz`oqK2#n5ckOX0lk(4c%0K(%BQ9gBe>EnaS{re9{E@8&FEsMLXkp-? z6-I5QoMZ+Z-3P5{u0w08YwAoX>F03<1eFhUPNwp0I7TkbHRJI7IQ`>m>P+w`9d(V) zd?bQVBXy~t3tBbP zoOqADcclBg^*Zp$Gfz$6@%%$;4PU7_nod%yOV^=1A1S`3qw;*_=PMIGaiU7TrW1O4 z>`jFuN5o{FS5h2JldhT8Xv{fEGucivuIAskb%5N5)VNjiqh5vjzNPt2ro7ZjNA(;oDF(D~A-p{dvP-iEX$?h~f8 zpCO%39@vJgMe`Zbe1>$6<};-8ee3!rSKLx*aHXci+WRE5FZ+@pUpa5t+K|p~mk*ig z=-suh&ui`-=9Q_^6uGG2~nn{h%_pejF?m_d$bK}}t=~~)x()xN{+ru^W6_;vbjR`Nh92lou|H12$ry;f6#Jq# zdf`NLq1Xk-pey>JC&iu+7=ROS9L3|%2lH_bY!q!6iql0c&Zl@jLZVRAVHpa=G8Bu6 zVmX##qF9PjF-b&FgGr(W1!6SDV;n})Hyg)`HMp4K#pofri(ld@bQf1)kQgX_hjkbz z)?thoD}IC37%NueIN?G7UbyIM$4CsvAc})91gGL$oJH|0j6fC^;tYysU@!_X2~#Le zK`}}&3zZZrQHpX*#dM0(F&onmM2KPtGcXYoP)4x~6_|sWD56+|$#@NKQjM?Cw-$fL z`&dD71unn`_%EUqqgaVg@H)a2!}vLtpc;)78_|s0aR=3SJAK#SPCSUKDPE0V;UPSU z%PC%t-{T4V5o;-~#bx*fF2to2FU4>1Gc3S7it}(b&craBLh%&L#jnwV>nL7_=kPqP z$Bh(k#4~snH{n)_w_+Eb#vibr;(9!VD{u++P~3wAefD5C#oc(EKD)7#;!Zq*hw)eJ zptu7M;38a!?G(4;KHQHawo=@RyYUxn!=n@*#a;L_9>W%jTd)DE=oNb}#d~oruEAz( zqPPh+;AY%|jTATHHr#?g(N5e#-`mlED!fGTB^<$*_#0lK_zDiw=N0UwxEG(I3HA7b z;urW2eZIiw6hFs@IDpUaF~yJZZ!AU(hbSJxzwjPD!a<4$@iu)9Vn4`@q2d%Vj^a2m zUbu0x$flSr3UHF>D@KZw=zA)m-eNe#;WX+kdWyjm2h*sh=q3hG96%!{zCnMA{e_3n zcjza+p>Kcj9e%)x6i*cW#E&>e^rF~H^brupimnv9iW9_iQ6d5q1EO3^qbIeLVyT!R zrih>@qF5x##7yBA6DUp)lf@`hh^Z8(im@1jDRgxV%0wRWF^y*BV}{5@4yKb@4$8%8 F_#fQeyygG^ literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/Flat dark joystick border.png b/examples/starting-expanded-3d-house-horror/assets/Flat dark joystick border.png new file mode 100644 index 0000000000000000000000000000000000000000..b4e83e112eb9375cefbb86a6d044a972f8bf4dcf GIT binary patch literal 3751 zcmV;Y4p{MtP)005u}1^@s6i_d2*00006VoOIv0RI60 z0RN!9r;`8x010qNS#tmYE+YT{E+YYWr9XB6000McNliru>IW486)D;&{k8xA02y>e zSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{01gjHL_t(|+U=cxXq@+Xz(3D> zC+SX79NUp>$yVSJ$>iiJ))lIUFb5nqkA@bSF^@SUfk8d!SOYF+9(=fJWpSxPJu{Ww|g-LpUR+CJNoe0RD#-Fx?Z zz*x5LUcdLeAD-v?eDC{yUoebKL@WgNh(uz+rWQAX1fn@1BG3aG0qFpq0NQ~LAn5&^ z&m55PexCtuflh)EfITSm(lNuxSW*0eB9GRYA65q#Of&1Dq9i`D~*IS=R#gJ@af2 zj`KC(dEj6T3HK;6z=yyua;ooNPMlAhfPRrKIz9et%)c z1gyd4AsE(!z+VD~e3a=*$&6<}hm+&y&zOL1TFX~8+}1|tj&1;^r>?WOFkkB#@jqOZzpk}x=+so!i|#vw z1TNINd`->Gbad{#`{yS*chc0{TV(oQ32JDOOiy-oAe7JDH zah!rByuFkmm&@Tpl8C;TyjZ>UhgB1>w|{Uz;55*KQOisyyp$Rr9jluX+#4Mn5;$k_ z`GOvSbG^~(%okQ%z^D5M4~lS_hwmaYYL|8qPCwm0c+l4+`04(^gASa+RZjp(-z>5~F8*BcRuCoU^i9H_Rz~wGxd<*~fr=(R~rG+co*> zX-o*G`}XdO)N}^ivp3eRsvpyMHwZNfNmTwInTVHdrFGddU?ds~A~t>^m~ zn{H_|GKhY8qw5JbRDvVXSO}4mCSOAmLgiE>8VhZjfZj6t0lO9rOVo3q`X#uxe{e|P zf9x6m?aypfs3UgP&wha;CZDmv zj`(QFC0O8F7DHo$yuRMIBhK38ci%y5!GW=H`n>1(6`27=Ubom8W#VX2O-OJ5vmJtS z#kyakOt`3YuGWmKo&m-AhRJ7?ksvDzSqdw`qI}b0W|Wz)7gU11ZFE1icp2qJbGau| zpIn$&KLd&!vQQb7Kpf|5g_Phwwon-r;)Qif@SZ)fb`9#ZH6TW%x?yo;+oenKxm7cu z26V{eGb-5)Yfy*QF2TZ(#mJ~;8GdjK_`Jo(s4&m1ItKK{e>d^Tv)hdN7zf_XfEvv0 zH~EZei~|YifmKSd9I)6J)j);S1Z2O3#;6hls|omw#l@%+U%IaeiNs>T;F2!d7|^Iz zBjPSfIGv8W4nR{T+h_6_)oet9ExE|u60G9bvptOJA`;CX14b+&Ms@uok}se=NZP0> z3cK?JR1?ssHc#aVD7NjIQEfW%OYnwwKiIN$8#}so<2a6mwoY*zht95DJicvvIS%&( z+?#rNqV&O}u)T99ZEY)$2X1Z&ky%`@t5t_Iw}c3XTM36-2?m?^eC7tKTI%82^93yF z;nGeZKsHwS`?p;rsd<{%XC`9+JCuwSK zF6HgPd;yEffZ^6Qc6Rp=2-=q?jZPpKq-$3X;kKfSXnVeZ1rus*rE_PuH5*1=AK=ir zql-|uwfJFN(eF?TxUrUqR9?W$;sP@_uA`c>h#LUpayh1_uCutXP_lq?#k^@@exAvz z6J%Z2qTk?TU6-kA6D%&w7yH)x?g=T{q~+z?T)%dOrA)@ILW8ojl;QfdD=aVHF6Hf+ zd;w=lO1;@EHzuz#Klg=QjRs?3evTX0ua-IocsB#ynMau~^(d;!XVX)-?lLVcA#N{O zMyywEFJ;IqF0zza;MVNTjUH|$U%;7-9_`l6&+Q5|K(ldU@@lybcPp<1>x_lhs4|mz z0!rHAVN{tbcLh|Kuy`0%=IXr+sA?I|s4^?gIRK85uz(m<)lW&@6>vH1q$y!C+AvDQ z&1Rf?0;c0}7c2`JRU?s3$KAXx7=YhdT#PF5$(W|=QDMf`d`<|$Z!JDXh51eXAMO`0#|IW4qr#kB zQ$WeeSsMo$6(l3BtSz8dn}20-GAhJ}`QyKbOYjO-hK)+`iwFN=6#;WUw>TMPYV_>nTXE< zzqGg+W#UX~JU&x+23$#*CoFD8nHXN{AJ!Dm4apf;SvGAL8z7w=A3amFfZi(UVT+%! zLEc&KAJ^ZWP2~hIYcVuRWY%kFOB2v*Ml1^&C86+R&!G}CARsDl<87s77)6jl<@lps z^hg0OCE}Bo1&tE2-*9Thos9|TWx?Z?1&wlNzk&tyvfy_uu0}btU%>);9r4@N5gP?C zDJpLj`r<&LFZ_IFGPAw2>lSdxVr;C#-y{>G9~S!Jq8`)Ww#W(W26kg@;_f5n{Wc_E zIv#gbdClT%tU5|l-b^RrnTiPrkV=e>06(;F8xJt-xj{t*^cs?HW4o#vdBxFHIabOW zOA;`dh|em#X>m6I6#k;v(pz*F{2(`HrhdP@v#T4}ZnB=M#!e%{1V+@3mASzTxT@D96d% zoS8bmy|b$m_=;VchTvaQg4 z1#_zM)l?#0_Jt@;CC)Z=@%)&=%h>cxJ&;l5~~2K|5#ML)^+@9v`f+2v$>q1ykkZ04u#>mPg-c-Jo- za>tG?THDs|qvq$n;Iru|-*mbPucgLE|8uiWKsGx9y?ggXMdc(gQ0rGqMA*^2o0c`k zf=ihUHzu#5s(z3!p(=;Vv82jZCHO&ZPEXBj>FEBEBXr_}<^78b^R%@+hU45nho5y_ zrY5hV{%AgiU6sS17Px&zU1z}ivf;{n;g5hwEnmH+re=2T>bWbSYL3aP6D%*^u66My zRCzO%7=6EH#@4kIotraL=`9`I!?m6bbGayN!>PpR`I;Km z)M~VPqk{)T_yG{B)pHEDwxSA|#f4fHZ%mcfO1Wvgp#=npL}Q_#=n>!_fG&(;m<9gM zU6d2)bi8ICIwXFGq_@)gE#P%*QNyFi0N+LB?P^ad*R6ne*b|L)spxl1#MQ-97)IrI zss_5-x)g8~5&s<6YNeK8Re9S_;`v&@{L-wVM+Ck_jZfWFfF#N=$O%7`+PW0*ei;W3 zBD?|oQ5~0O7x*R02{$8WYPq>+I05g_+aK#d^&2956F5*OA8Q2o87lAjIomaafDe@D z2%?98KLMWeQD$_3UjZMGlb37exR7 literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/Flat dark joystick thumb.png b/examples/starting-expanded-3d-house-horror/assets/Flat dark joystick thumb.png new file mode 100644 index 0000000000000000000000000000000000000000..8acf179f8660be36ccea1198105da35c07154fd7 GIT binary patch literal 2939 zcmV->3xxEEP)IW485iPkW{Hp)}3kXR> zK~#9!?Oj=H8`l**_stBok)rm+alOTHY)jTcOO_Pdau+1&5)^3yq%HEtw|uhZ1*opyTSlNpA;d31v<-mnz&SAh32>in$=8J7LtSkrZm$^ucGWa^ z6!RueX69Q&R0kk4#epydaJxA@{SzY5+uL>0ye|c)so$qD^Rt?!y#%6%(#ihjpa33} zwtSU{|Jv1dLf$t5RM$Q7jHcj&qo=AHvH zcS_s(QP1g?WA~H*Teejd`1Ae0AQI2xJ^(YnIXQgmg^QO4CevPk+J^mmiNyN=@{&o4 zVR(>{nF#=xot=SYCOvlsnbnh>CyyRZO986tn{)y3TcPRC1JIJzWrHBEy*uVBgT{=5QcnwD$<2%zoR zxp}=+b&ZuN6`;C)U$gGXI0B%=iDW1=4MHq^%0dWen(kC?F4y&pqt$i$8dD-bZNvU= zX`1#vfc&(oSinvmE>F|7LxINTCma78=>)(5BZ0rEo-~mj}0bVfbBa1dD(v70D$6j@OmKx zgrIsyW}V4A}ur1`-h5}JruV9n#c1v5q;6+E@4)*S1PWL z%YrIv8+DJz(+Q$Vm%0RkxzDn!n%<5UJ8BOQLNtJ=!euPs-C!qx#;6vwqavW`y8af@ zZ_dtrA%SifuWhdgXiEy9XJl*u(H57hq~(G@me*Unv;ew(5P-*}Drqp7Xs{p(%Pf0~&CK7p|zqdWKpaih*^GR zUH~Dque+Q$3qjg9?+}0*TuL170z&KoAZS;hvEJ}xoN_5~9;RsqgsvOz&_k*&i**6BnP*W7-?<3WC5F?_yU*p`Lh_$VeO zLg4h8mF9dkLj-?b0rCn8p=lZ-;Yo}R55cmmc)nXgwGGX;i74unL$5CvW#tcmKDRi+ zG)-I`{20t?&62-i^Hz8~3rFx-Dcrhw9pTA|SQa!PD8_0=B0}jRvUAq%?SpLZ((6-%5XkYyTE9X@%+XK7 z6a5C6t{cf-8k(jB48t&tRdF{z6cG)v7C>8;1){Y#jz>hWZEIEBeJTKR)L)5&C!@~4 zkAx?&RuPFrmfWV4!sJ9KRzI=?12fTfky2vl=JiEIFwI#E58Yg|0^GiJ1Lh)8u9U*i z&1*5OnHfPHzz|}rb_`EWU}k0-Ma8Aa@%kX8L~v{rq2Sn>^#41{&8wF`MsBVjdHIFV z4Fi*t6Br*Ij`!IWA)T3TQykCnu`LU?Zd{wY+H>#S+$lmRIF3+oeA(PE^N;}Zjb)}E zm-R$(!+b>$QJYI#%1Wt0!N4__iIm}tur2eP%R_2lTh=84fI#B`cZ@j&`Maa_u$Y^c zqTD>-FqBfK=7%Dblpnd2I4;0D^8%12K7f0x%TfCwK_}(~7#|z!0bshkI48h#DBL?Q zz}1WWQ%b4BE-%hNO8LRS`L2n10RTV{{miu?XQE#S@$-4!Kl@`U93BKPOm0sw$is)d=)x_l)%__?2zYWe)< zcL{K|`;BCp8ZFJ5c^$f{XzIlF}*ihfT{o(A{=yRkKM}UB8{_Xzd9F$F@0f z4?#+aU~qiN?ZNReNCyO9=8nmU;6rCRT6{tZx4-!*1W$G`LoZ*uIxw90 z!Xk;N3_Q}H>)M+_h^l*XOh>6MY1=>S?YPI@DSy`x#_pyc=(_O&-6KzCXXZ zv-R)EFRdNIuDT|TB|m3)JU=C(O-R4xmdwl_o9666A+$gBo<8A7J?l6L+be1_gl??& zWMuqhu42kcCFuZWm{li0Pfmp=C(ieE&N_JlDUHI)+NLt0(OymHuaKY}b7e6(K)Ph+ z3(~e&(xyq1=9Np?()^x2O`1AQ z8a5c7FrZUP@05gciG}~E1|*bgH9VnrpUx>(iET!-DV)$@z<`v23FU?-3{L4kpnIR* z3FQ)!izX%%PUy;^{W}co)1OJVfdl&vC|9gl*X{$m4eD65Q=eYNdUfxS(z#o)f&IJp zN*T~CVFYLD)G1}afIj{Ic@_5Q+oyL*?}1H+_T>^vCMB0FoG|e3I-yDRs`aWi<~2GF z>e3~pf3xl>L;k+VPJIUT=2}XYN-oaMy*fO^RVI~AELEE8?A4u1^O_3}PxznbF7=;t zH>+8_xMvTu>B?>1M zEm^#HnG%UfrOTEmQM`D`vLy;97A;$*RGG3RN|q>Hws_g%iHRlub7@65K~hrj#L^{7 zl}aq0n3SAYrf`v@qDf_v_`l+%OO!31RHk^@lp=|x9VeD7o`jMmiYJy$ER+2Ia$Cv& z`)%>W{_nR{wrrUaB@)Xfb8V$cB_$?#6J^VkDP6Ku>Cz?3lq{8)ROUZ7kytb_F{xB? za`DoMY$(MACYCPE0Zfxil}s*Ex_H^L$z_xHum9ze|LbMMd;b6bzVIH#TV6DgXaBeV zT$qpS@8|aSfBpT*^>g?42bqs_hhBWf5*qdF&^v`|Ey0sYd1zq&4tx}cCk*P{eIP|b zuatp&#M#uPf1h6My7nB{rCnb>z1;_PAI!mBI`kZnGNN$8e@6d&j5`eE6W(#qKwoHh zLZgOFYB#Ojut7pOK15AxK2W`3!^Sn*B_@m`&c&PlrW?%bWl@b`zh z7t1Z7TnTTE*YDn;C({vs-$3_X9lFL1{QL9Cxq7jv{#iE(fA3W6!M-V7S!2Wh%Llpm z|Lcyv`2YQkJl}ylsX_hYItKI^)V~v#o9Jt$Hc9_(lKs+1y_J8SQQwaJ>!%Ft(6eXv zPL2Bv>e{V0Ujsg^jvWT1RPWQXPyeR>yo58JObW}I^ZS1M*JJ+YZpkCqFW%gH`V8#W zy;HT6&g~MDcoRGK8Pu_7N|WxLQ#vP<8`ytP3On}c->XB<|9O_A5nglZ*WQ0VEkpYB z@7b9%b?Vl=XXpMYe!V39y$=8HFZlP@oNry~x5+;@?-xzIl-^wjcH={lR64nAVu}B= zi{EUq+uz@Ge}5qU`&ZMyPLP~jqHKx3pZz}{i2t$wKRf*M^_Kdo$%!S(B$fIJNSEcX9;P*P%YQgWI98JiQil&{aw^Otm>zkU)EhCI zLB55@aUkl0(eEc`hkfK;^p4yUwb>WVxyZ5P7*vDT<$u=0z6RDs){5F(i`rO)dm>jy zy@qtV`@IC`yRZ^mTv6=~9>BiE7F zkX&Y(T_JnXAMWF^rrTxhwsho1@@kSx{JUO9 z-;UZ`k58%Bl77GbeIKNMUhE{jza6BeQEw;ZGkKAe&+`RRlc}F4<+FT_l+X4xQgf(Z zB{h-ySyH|q{+TG>L;swV@99=jeh#;g^7Fcx^z&@(=XM#j>vTCO*YeY(Tu${JFBudF5I_t831qo~)D@_TCoxiM8qV){3z&8P7;wYe&4zxxj|(?aS4r2O+>KdC3F z_mO*}o=o{o(WW`@&~_19D+7v&-Zq^haNKY%S)Vrw072mBa?L!e(qk zf0V!n*qNDY2YtuwYUTC!}*V#GhJH# z*?=t0c|E2B=YE$=J-^rCHMC{ED7GD?_Zat|$Lu}QV?6hZoX7Kf&8EHA?(2IU2jM+< zeqYn{JYJix<30O2p4W3WBV9|bA=g%6xURhRPq=5V|KxRi7iZ-=l)5=}3+5T9CuL*3 zFu#S`%t%^iVeY<}$P1k7Q;xYh=GSKDpS`GmV}3t#kMVpySI_w~uj{k6{{!ylKAz)v zoX6|&eD+?KujA`AruX_hkLNZ$)@$%SydPgb6Sdcn1J~nLJjwia&Xqu&59f07=U3!y zr1b@6?t78ULS{w&m>=asc{_D3%;Q`hua_%Z*Ata(D`&A}O!29+7 z%E5i7u&?{OujlmK&MJ@vaVIKb4>OPVJY|Eg>+7H9{GQ9#_uTfL-|KUKU*B_iPS59O zv=-_6u6w9`|J>dHzMlQP@ICdjTZ8oT?K7jBHl+6YR3E;M z+v>sVbuCb7@xG{i9cP2!IXvh6@LJrKIv+yqJ^1==bMCpD!*ltX&OFw8 za+`C{=QiiwhufTcEnbJO?PsMu{2cgw(2{hW+qXq}xK`RA9ejT};#T-Rbb>Sc4)A;) z(+(czcS;M=b9>%a)P5&=uGX>L&qxY9UlnwQGq?A|gK#zgec}1s=G<#>)*D{C+njqX zZcCkaqxQAESGPI0_Wa(b_vba+o6fAgE??W%@Luh$2VxkSh7sgoG{R6cMl(DFXZ8=n z<9gr`bVo0Yg0p^j6n)^fk?0!zXwrRa@jdIG>;8G}pYwS!0vp+O7Mt)X&fznBfekp1 z^>F)Utc~14u7TTr8@DllSc!qom&%*j;EROy;asi&l3s{B2cq?)_c@SR5I;?@$ z_&&T&=g#a+kF)+L>Nlc3Mt&TQk|%KiQ=*GH` z`Uu?DV?2+&^#qKA&v-2MVmx+ZA|{7DF?)@iidTd6MZAKU*cE1xJFx@SbFe*fF8LzN zC$R+c@C24c&L(}v_6K2a+JBBy_$2BNqW>_`{zTNr$!u5horPM+j@tMT*C7Yoel2ps zSteW$XE#Qlk<1VCYUGMcPv(x^`l{%y(;`pIGLuDc4KhSsh|CJFB}-(vsO?L^~g}^tYof?5z{<1NCj>FQok~xH)?3eE5xR&hp|9YG-M1 zCH|yO7isUa^|?Cxoo&{?k`u^@n1peWlgYN~!L#vpzB%j6eXc75h)W^sN!V$7L_TqjtL({089mIWT9QMboI$0HN zGaE(SkgSY7Xb|}tSs!MN$eK~_B45RByn>3j6wkCuE>De?&%V zd+YC`xBeE_Fn9Jl@=^av{v7p9^l9L={K?F`J8JtosXfjtjN6eAby4ybn2D$mz4bYc z$xWUm^NT!Lp=5uU!=fHe_6=jn-r-@g2S&hp9J)n6lI(&~T0>5cNXReeA7g!+kx* z^VnNA#zCycAxy<#OhyyjAEv}?64@LRgY|lhM+>xyx()dl#=yEA9*yikj)vJ8-O&;4 z(KE6w>2tOB+1i`-`*D)@yin9jqQ8%{ehQ5uUm_dA+!b|wvH@PhD|i|8;PzKT-I&!O zmtzHLN3M!`CwXt!PTqrUsEJyr5w)}DQ5Ds~voR}9Cc$lHm8dI|#jq8XA~%y2VU~z2 z8TAHo6SiO@is0jTMn0<(*um@tJO{s5?GHqqOuEh9xu1u%*oz@3i#6~w{tXJG<9iF= zQWqp=ec#r7}B@8Rqset@%|qCZcj;TZD^{2Y0f{3Uwp)6rXhj$dPTiM*EMFOcV= z&P4w;wbybvGEda@H&A<=nHM>cJ?fju>tNNjKdHkpq8Dingfby~bjeI@xJ zY5y1bC+w~Nz;QVH9Vg)IQ=Gy{oQbse+4@|aeH`^iWH)Br@gTZH_8>dM>=|`0vSS!R zwhz6@Hs}NEhtM+mzT^YwhyLhq${hAfE{1$$40W zd!w#Ljz$BF!gM@}$(VtOaP}CSPmOvS=|1+>eMY0l}!B%WW1-N}%C?B(O;1QtIdyJwH9ny}728jcr{U~4&cN9h z(SJyO4fB1Ri+qnfAHDTE(ObWT3o-kc`~x51gQ$NaKZVzFGV+?J?bB0xoS7L{A#K!I z$iLWTW<}oUtq(B&1^e(TGBC>+t|YI(pE3WPOhCii7J;}1@5v-@7JIbSC)RoCDNP%@# zbdIb}c7j<8bx{M=&>*r3>2tOB+1i`-Yw$Afd8VjGN1sGmk3nMO60#V~r=l)G7RA$8 zhNUPBw=WNcVs^c^Bs34%~^`qjokQw<00Tjad#d8{B5*kNOt! zI?Tq+k&l!4VCIaxKI-Y@Ow7UzT#KFYjC@uvVG*+@F%R3LPmVf!Y_oSiKMzx|3N4Tu zli_Fl4P>~QuL@j)D{vLwWS)`Cgk#ii#lA<#x8dv%-hs3CqCY@>0&^eUkK9Xs5WV&8 z=&fJHhcP=$Ucy1_kNN`nI=q&nms3FjB_J${5Uw_7{=3LfYFp2ynRCipr&-!I7Z*nl(G2xn)p8P2xi zG)^Hi$JkpxhtKgDUWhzNo`~N1V{DJvadKzOc9E~)CG3f`_c{BFo$ZMFMe<5sH!ae^ z+WdvN`8%0fr=kCozBJhzWzYwu@GDBfSy>d1EJr56EFX0RvRJ4^76}!}yHN?&_u#JR zE0cGi3aTOzP0=c{FxePhM+qcHZFY#>eXTpex<%B@$&}EH?23N4KI+_LBiw|BXp8&M z67BE+oHc>-)={@1-N)Ygez>p4cpiJ}?#O{`@bl7u^fObB%#NI)KIyD3Za|%2-5>WN z7xF}%m#m2zu)Z19BlDBhVBUrTxD~gcP-H&R=W5>=_NM(>tj7tg#s)ZBiH&f!Ir^u` z7hx{LmdK~btJAq&D6HcNJ{CwZVKjXDU0kp%NxQIL8tRQZSyqmlg zW}&DHledIYWWG>@%!8t^E{z+bFGl7>B9f3FHBdJ)FIf#<$L&an+Pp7%_qA>U>)KJ@ zL*5^1k7vd^RzW6IMgvqu9W=zfa8@18>qT9kbRT=`ns8r_@jUj{EpR2Sfa|Xk z=^Cs+ro~mEBI&F=(xY6k?uatTfNP@8OqN6mSZ6`;$gE^C%pAytY`6|LMP5t#T!ROC!@S@hP^qqm-lj!B&jMHoS`0!cKBKo`>^i@iJb4Gq+nidl4Sz z{+`F$*>Lzehp`0@p*ZVr6FDqqo5_daY$P^f1745bdL2e#JsyjGHMuH!>y;Q6vlZlo zm`x_9VIpQk+WTyMuFl3sJ(j$HMo1I2xd%fc?FVCD%m$I4$7}#;KMLW@PQ7oHxSzkB@^@4A{)TFG^jo6#_fy-jGBWkIQ|2>x7XE(9 z+TTs3{+4QC^v{v2umb*eO4k0a=RCZYb@2M^Q-3SvG5%i4-%2@4t^Li^G5C8a^C+fZ z68znioca4Hb6V8?hRS+>q}#0JZ;DcXTjlSe{4JHgn|cSSy|uru@;5I&PoJxNJ%2xC zdJWe87G@&$!rxGt_LK1%_C(rG#dN%ai;@1WDz$c7>Tjw{e@Er-sr+4)wZEsb_qSF4 zp32_eR4v6K%!j|1^7mCwU^cv0@7do<`P(ReM|A@JmdZLC{~js_?nQRo1OMIrb;t>~ zU5o3Z&qUr3{f$vO%MbgE$QAw7WNzFVv#ZEFF-uF{6n$p06pA1Nu8BG;={5NqgDfZq z_mg!6B%?&s#iFl7R>8O2-}k6T{Uhmi=czM)H|1}I3NkYbk=AlwkGY#Hj4~*T(kPCi zQ9Jjy5`IonejLn%Qhr|Ur2dAqzl-{g=>46PbNkzI8|p^-yD94g{6uZ< zZ>X%D-3)&>c2?)G}Kq%N~D9om--W?z4t!>J24UCqMt-Q7X9R?r;tyOd`Vshk@4$GBh5N0?GuZmCdM)*8JQul&?1nCQ zAvk*p=7Ul9jQXiaw^?gBdSfXzV-wb4e9*8_bHbZml zjdW(cA5Ee*n?`+*td9H87;bals;G=cXc%eVAo@LI{pepKRR=Y(8>&r zf$1^UUov-FMQW9g*#UAN4u_+pGruzqk@h?B9^OZ7yo(*Uf`4yyCCVTzO2gj*{KdAb zNVok#osP8sjXFJPe>JR~WsUw9>I~HOKT&5Sv%%T-^w*HizNOAY+W$^{Cz%gFQ~wI< zH1L}C;ZJ6FlkO+$!brgFQQs1MQ8E#qbIfT}pgv2w-FfQl9J33^&CI-sw3hpNOdc{X z3ZNkF!fm)YYUlp8q9gkr$EWahoteI#buN5D?|Qv~`ZLo0M(XRMKSl4{J|}XZeB>GC z*4gm|wf%WmJIjKLF}s%fOKSVf)L)VIU*j8mhaYeWmm}@H|G`)be-kn=`iIE=(GQJ! z7&#n$Bgc}xVLprz=n-|dsGX(2ekA`v1HUhw^1gFzSo_j?k{u=HQ`JnAR#bmSbe z8Jc2caJCNS15vk(dU~YWtThv@F%65c2=lSg+; zKPF*HqV!)5?kPR$%e?nQGd*H za-WSbJ;wS3bGH?tR-u?ZM?QlW!w%A!-x)8E_G_^Rdr=m~r$B=r55su+OzPM|}a- zUz1*wzhSsc<{{lr)_IW~IitQV`kTr8c#C7+L1F6mNVhvroqfRUBV=S|W+JWSz8-T8 znHjl|8#f{cvPA9N-(nnK--CDqzOFOV*R#%m*Xa)-J@uQU{ngazqJNv-x&2kR5``k) zWp14o?^D}<2y175lE-8A2YDj;-^ov+|CIa;r*H-z<7A}0_umZ*(H&i)e~|1PeUGSn zlD*I|atPTTW^eRCo2Xkx?W{TM`=S#%U~I5%2jA}n=!z7$-xSQokmG zQ48~evqdoLL|rfH(UESm))+LvD9pfgOvbc-_12G}I=17<;A_@^=`~naLrpw_5s~)y z;9-o6w6Bf27>31>!=oM=z1ywpqag-iaMS~%zmFUM`zC0O7Pud6(F%>x2;QsrTouRo z49p~}L_dqH9Q~%Kw~!U#d*O569QjPt6-c+c-!{xad6bK^FB|>bsOOU#Q6_RdSqi1G zBGQ@lDin{}ED`k@@-`$P8E$jmTX72#Q7qEFX!K8$MWSCu>TcYD?No3xrkMNw_ zXDLjNu|CS&ZTYBmQ_NPAE3qzYAf5T0v6i%7i0AM;3gTHTz-KsxT>NiopOZI|x$z10 z>DYFHJQMwK@@({9MD6Tr*nfy~(Z5fg$2T#1hrAH8x5$gpe@v$5HUA(#z(=tD6ke0R zc{oX4L%N@=Gb1goiuy11vCo36c#VD!@>1_3-R?Yfc7Xm6eu?}oYJ2zfm|yWbGH_f* zT#YO7Co^m3*|D9zI$nXV>&*1^tbeB7g=+W_uSWk9`9t)(BkjM(cesgT&Am~7OYV>U zVAReo<1n0kiKEe9B43aG4f0LAjdyVb$0F^${|9)zDQJOauy2W`(YK1aHQ5G@BfFA~ zV75g&)Q`GO)XwgKeS0*)eHaw18^ZV7-?}u%{cyjB@faTcS3QjSA&iS0LY6@(ObE`V z!Ymhcg{b>Qy3JYxPzil83XfnoM*gd}9*Cj*@5{;Lq~L3ofax_@`|l`9l6}xC(!Ml$ zqIaZyS(L|vm=@V1>h96I-MS(wBL!We?i_tpvJ>p9qaJFbCK{kFs-X(JSMNCqFZ2G7 zCKIC{Ll%pENz_k~Mc{kkb6*+W{#}8|cmr=C1ONWx8my(hf_#&_ zn#_n})NjN6j^Lf>50URi|6bJ2K7suKydV8O@&kMtv)$x}F?*H#DEh-ja(>pemOG_-9GCJ5QZGPyHg!MP7*7-hDmh zJTBrV{EQ#*ExwG}xzEw(xelA)>-sv*Q)ge$Z^U|>!RF}ClBc8J8fkwDpCdEpFrSI~ zxu~7J0Q=8y0^8y2W9*FnIQeq)yU17Y8unlZUW&B${?qY#f0DmPot8cgN~0Hg!`~qE zL@AVn+sdGL^kvDU=*vZ2o~(dkk+sMoFe{=G?vDDdsGZ#o`^rc}Q8W$Kh2ifZyp|G3 zhWoWbCv^B%-GaI~QX-p?*CPkI250?X-WYZ6s2fGP&039d6B?o&+M*@e{HwQa0zV6W zPW+9Bd`(|F8{Fp1&qsE$0qRBC=R{r9kF>u5xlkMZBkM$cZ}e`r&V#(DftpcQkN#$| z8tn6 z@|oyYk*{MPmSaWK>&TPv{a=H(;eN7y7l&~)>I2cgPkxB0n2t{|6K;2&I-5m32d_o$ ziQ3+MJ!Uud;!V7TH*f^|qjr8A6YvKn!`Jn7oTtuSrJe+Td$J2tqJM>aIr?dl_Ag;4 zK8c(W^$zlJ*w2pI+4FcJX3vrHqJNfrGWrGNLM+Bo%*Fgjd+&cd-orZ>hi{`FOMV~y zn5doo0H60ak-jI^kK#vo%xHWN{V4LI=pP|Jj{d8tosGl@e2IrK9Or^Fw++M4n3)%% z9zu4*B|H@Awk~knU<|?;bjCoOihcn3VDvr6zEO7~Q}B7@*{D6veLjoK5_Lz?`nr&n zY>&(M0_Vd;^6OyjcgG3RHTMfn;%D^1UHtQ58?=SLS!j(raR=O10JlY7ki0eeyQ3~d z7RD`+rO13Ri=Zg-M15n_&aQ`jG33Y1s1dC5!rxDLEw>{9?pGI0aNob`+SK>p{>WNn zI$Vk7!C42GS4W*O>MD_LvsN`^LS-~W1JptNfA!YY@dwY*b?R?IMwc;W}Ik z@6~&L5{s}9^RPJjC&(qyFOAyS8raXqQ_(+8F2mZGO(&PfY%2M5^mEBwcn-5LC+Y>{ zG5G$^$8NZvtoLFEUW)pK==YNcF#?a^4UC4{ou|&mP>;pd$Y-LqcVCa$hG+3AUc)Qc ziRYtsei+HDt)b*__`1H1^VHcE>S1^YoA7Y-o5_vQkBqe60Dl+udgQ36*O8CH{;{Z? zt-`pNtt2Nzzk-|;{bX_qreOxgV`8Me_df*tum^+jdGv$G)6oxz+SwWSyg!TdJ+bbO zv+x*y2X-L(zT~0k`;bSX|0HT>z0nIN&=WoIL2%}_2hlxd=0{O?B_F`Y=oaa=W^h{< zq~KjNMQ6MneJ8SI^sUJDQ8yv)$6Jx_MeT9!<8Q{yKUv$>jidgHUTNqX;UwP2hv7K+ zX|VRY<0$ExJC9>Hhj#cSBmX>y+Gv2w%)Uk=>ZaH5=P32}(OWlVZvP`%QkOwFw27=h zwnKA{trT??vO}m&w&(xxwa1sD_IP>T)Y;E$OQuhR^{=r0oh(Xb!}Yi^>fGdYxE9to z;hM;Ne6sF1`nbnx`&_GuN!q&SpR@7)aG~L8#0AiXIOuQPSoaaLS=FyCg1^% ztw@fCIWCkZ$A+@xWAM3H`<&*(Yxf?0for)Q*#M^f{hT{>eY=huGj9afpS81=(U&3H zz`h(>aBS-OZb$F>u7VDc)k)WI39?kMb`2+z$^WWd)2^Xx%yPi>Y<(kg<62x7wd>FR zCb*XGgzGsW`n$>e(HADu;wq#^n#k1kY}%mw=)$P>M5^$EC6o!y38k-9dAQV+)+k*RCa90Av(>(aVN^sdcf(Yq#- zq8~+iKi-#XvJd)3?RvC#P4*(~U6VaYd)K7v(Q}Q4>(FhkOFw6Bb4@-Nv(z(Smd*@?7wO*SN_z|Zh~m>PW(a$58)qIUKG?nf)kz;v|6%;;T@ zk4N90oE^REu@-8eDkep`4ky61Xzd!buZVGxsq4@zi!pdC>iJ|H)W=GEk8iO9+i?|Z z=tVLuY5fAVe;I@Q^VH8pZ$67Z@eF>C`V!CR*XW-l*W+a52J%yw8}WJMCh`ovz(t(K zS!~9oV7&#GBe#-Y!`z1FxW13cvyPY zlJ@Cw4R$hn8*jxnXPNO*%-$rc)0=OgDz*7KDpQ-sP?7p5S)R1^99i%(Gczl8QJdNE z3bmONuTtMYzD8Q-qTWr~-$cEKw71TOwbbiyEA?&R4sste^DgYCHt)s(YO^p7QWqr; zlh$is?W{BoQLlz|SsbA@y)W;t3YmobsDzTyS0GD8UydvjeO@vTvPI@5bHKb2*TeG_ zLqcQ`@^%!$o&Tx}QWwCrs0OdaIumN(YGjDIR@BZ;aNU34XMBRcqF+E>!FFe#;S{c< zH!mO^wfQCPrIz(qSc-b|*5BYeG@yS5roHRYwdm*B_2~NZbLV=r-cGt6U5n0KkFHH; zuE#~uyB=Mau20vaYtxzQ(Y06?u1nXV{RS+I-gW6(bZwrCdK2k-bS<8bOkInvza?;8 zx*olD@4@xxTHG4xTC{dOx)$wSht{d<(zWQ!^>`0y?|QU$eYzf9i_Uy5u0@}dYxHUI zZMYtnlWud3x)$B;dUP$?yB=MO_O3_QpS_<~YuBgi(Y5Hh&O*J5w0Awa7VTY+u0MO% zqqXbP_2^o3<{ES@IS4W=(t7?+R+yv+LJq;aYahxOT6DYtyuMExQig?pk(TJ990& zuARBR>)2yl)2?HC*Rt!_-gCH)J!dhvj_qB`)S zUDI-#GuO3i`d+w(UE|KI7vnFuu3givbJw-U*}JY?&z{e89oLCm7Pafzwd^`~UAv}# zLKpsddMEvMyo|PJk5}y3){*QSz4hMcyO4*m8f$Shay|Jvc602;s5g^uhHd1JzAm{E z9xuoJP*ZJUofVBNvi0V0zB}7>vH* zA+mSyT)wvZyRYZ8H|+=DQ+$R&kvq75>#N8i zS&WPPf}8;JJf>n2uH<}joAc?Ig0#$LMxGo2h&@-n#y=2ut} z`8DY?=z~viGU{IB379?bab$P$ILxki3NLYu-$cKY`XlNUaP}=e#BzKPQpor59;`dz z-N+84+Tk6%9d#S>Ets8njaJcHzeN2jcHlR>!fY4$Dt?FczUX(8`*9F|;;*QWkpAUl zdvJ{UipV#pSMj+we;}VFH{qACf&3Xi;Wds~NB#)&hp>kHKCB|YgU`j<=X5p4dF|eV z>$)wu6E8>FzskHl`3hXuuSLB#YG;RGzZyrQca87m*!AS=VI#R2Z$@q-UBgdfWw7ps zrEpEB)~@NE7>zL)8})c{B1YhmsE0>CnRG2b0oU{6(LYJfh<+j29|MuPp3T(tYd#5ntn2g?^~hj-8m`k(Q9l;_8PauXe-;y>|AKUFx=x+V#B`*t z&2!YLYtp=kIgyu0*Q4vwdO`GGl8d5uO)iQ4E7JS%zWU%KK8gB7^sY(QqkRt?kKQ%; z6g=10a2>j>D^|d5-@x_gY&kxNOd;Qc>(ct&=sS_FL;DVJJ=(W}>(RaqUcztiGrS9~ zJNsAhNA&xmc6I=Ja0q|lPq-#sgZ4+@8nkykx(4lChtFaQHo+=0Hh9lfKzjqDkH0(oonW_~<~ThJ}))||I< z^y$ePac^WUvJTALs27=sY=FjSiiT){oA5xe&Wo0j`N-BVZ^k{`%ROYRP?LNSW(_f(V1>md#Hbj;u*TF1@HIZe>RVafM zQG1SIC>Z%Lc{j|FC=@x0ER07{BK1d zKncu4si<>C?d&O(M2@JJlciyLU*6w(EXG8v#ggb(lgpxCNj@F@1acgPM~)#!z#NT7 z;Q1C{O5}WU8s=igzv?;Ek7Ecn!fUY}gw5!Ofl+Ub+F5OMMGESod-NH}9x_sRiQe^S?fR^Y0dVGXaV`3sT!-0E34@UpZmWn5 zaC-%;i{ACPCi-&Zs_6Z^T9?H`D2M_W2G^p!>#hF_aTpQ3Yx$ArJ;xMyPS^Cb=;uZ~ zpR|4)GcW|crsuTYjE(3Q^&qkj?#I^PHfObwf*1Mx*Co5g%=#L1M}71{4>W?u*?T_M zwC6Ni;JL^wQM<0U;{~{`+mP+B1O9W`Ao#x%lqUV(2O5zB$gAPA_dO_$BiM%ncoRo) z2+m%IbN4w6XXYDl-(xrk_w(<|dzAXVcJ)X{syuN%v@2Mm2nd)Aa`WN zs4J0fcfZDP-W27L59PuwWZ7^lSqA25Uf){hs7sUAVjiwTO?=Dz3s{?{P>Z@4?m-r0 zLgtW;%z!`G?=t=hm&hxayWRRce#Eax%j~#@x3f5&)g^G{5qHq($-!QOgS^w*HS&J%DA&4;tBxDsB6*YF$Xm=d#J zs2_{jDAN8X`~Z9F8srFkPwkrYyq@zYhT{l&Mt_Wa0p{zNjk%bEX^}I@AsB}V7!)~) zbRT=`M=%DX@h~RCnaA4?3m)UFcl3S89?@H`i+(-%eDv1O!E1a2&qTf%wYe3W@Gjni zvlDRs4nD!#_!Q3Ewh-?7J~~H!KzZN2mEP&g)VPo{x zn`732bid`Weim!sy>7!QICJ|7xR1x0ZkM&&T$5jrACj&~>(e;IpCjfOq~H{~!uz-n zmm|HuM!{#$F!)Rw1fQqhck(&b3qH%b!Drh%oFtotx5zrd_oH_3J-j#gp57CVk+p)K z*P8J2Y<&c!@e0a>SIM%$wO%glCjB!_dr%?lB`b!H$)@2r*(B^ED~0`J<#2$k5)P78 z!y&R7s>Awl)SrrE@0MNE1JDn?SKDzG1>ke{nfpF$f$u>s zc)eby*Zvf|ZvU>{mr4J=-Y?0Q(17|DnD+Iezm=>D^R}qXI=B<};P%LSqpnT5-Tm6Y zc{|iX0n`k4lQlwNvO3HcxISxr$F)==b7491pb`FH{w=J{mpSG>>T+m|+_(WZhOA@` zWWX=%e+{Xhs56spxBebiP^ZJS_>DlCAFthtx;3m@^Y;i_o1@_0 z2fY`2ke_)X*M2x^Gl7}g@{zBRiIJ&&GW~w$?t2Hd`PZfJ`3|m)DMvZ@o>xzlM9d&*)bA+#(&_t zN0UF2KjYWvt!FT|znXj;W=718%tT%nz4hYguP1$-r{EfT8qRJ)7I+1lOU`X^Ik-K3Y#}X{VQp}HBNIr_0n1xZ1b4d5G zx1NM)n1b z=bz#tKEWk8bK5Go?GaErQR}?>qS%n+Km|v*5Gs7%q?c!ZEUDc%7^j-XQM@Z<6;0zbD#-FUYpxEwXlao2(PwA?t>B z$$H^EvOXHX`u(W=uJg}u*P(wVdLOP!@56QIz4&LS-z|r!N8(}lUcJTp_bpi*K6jtF z@54^`9^3}6*X#7!*Td`n8Nb25^ZpV1O5L5T0Mou}^p(giFsnpurl2}HqH1KPs5_Hx zcfW_=d>A^QCfbL4$abMN*%oHzsO__&4NBr=ltvHa!F5rana~r>(F>(e93?^#G7)#+ z2HX{Lk_F**>uk6g3Ah_KMHY?PbL0*lw9rOdckY$jV9<5 zd0*5G$N^{+{cy4``eOu~kA!oN8Hn;26s{x(V+gDtU`<<_+0lYJEz+SPe&;>^6V_(s z*jA3b8ucSn`-b#s;J(#J_iqaCuNE3d)*#*PzSbV+Hha^V^&gxkBiHp8nSs2DS$d2^ zX8LQwV=r2=hGwX}kk3%?zFCq_+=WzjUcR%|- zk%reeLb~r+9E&_dz5(-e)U(Lxm>aWG{s z$O2^H=&fIjKAH4&cA_M9!C4s;g4f|S+=i`ib}QDx*~;i|A@fCV{UDYjFG|Dndd_d~ z6u!pe(SJ*xg!vt|<0b6CGm+1ei?ALWu^@6Y=|1+>E3gKuunb$^%;W8s29I$zJNh}~ z%;>G(jQ%b1MD*4l!)yE=A4UEUwfO8om4ehDnjX zlYc~?T4!P3&oGhs1-{#-kb5u&e!i{uVJu#S+o$23=&j$2*?7|Z4#N64UWfPkA&$bC z+YiHiJl1r(tlj3C%*1tFL7g7fuF+p&t-5X}GryX2U3wowNWW)H?{9GM84LbSL9MjZ50m;4eS_~upWu7gJNTaV3VsfIhHuCo@bhf#=e7+_qir}t zwhL#;_TdY%L-2c}V>nNC3Vu%vqt;&-8ZMBX!$mSBTq3)KFUhXqGT9B?Vf|Iqe%C!h zofmnKx-PvB*P-{471?nL^D!5`SD%u8uQnom_C9mphxg%oPz7GE*XgzIhu7VhV{)Q7 zvLOdjP%6^CQ}kuXjxftbZFWFKv_<*Ic2Tz{-R^z^;e0UKpfXyAs${EBooos7BLA#p ztuI(dEy!ZnjwE!&C(JLw+WeYhx>4VU?np!t6b*NgcjFeEV*gu7ou$5wbi4IAEX2Okb2lzp$6r?@v7d*1vOY*5>-G{4)&o9_A@1P5l|4i!Y-#%QACY z39=G-Ph@Ien|>d2_pLzf{te*$RYASTN~GJ}*V^OUW^X#P{+!p(z;#`wzMAYzR>Y%h z&qSXwjG}ioG3Jkv$1xI*U<9tkW$cRllDrhX^+miIGwTc3jeYn6XCwEJ=WrfwcR%|- z@D~oieb3-fIk`=yQ`dMsM8(OK<~Rlb+Xe zevL)=3e%$hhWrTTw|EXO;(2V2+(ypFYOKZF$n~WA*jqn^6HYN&K7)S2XVN$L zJpI0t&#`y#S@sG(+o9CDg8Cs+KcHvu{pb;V4<8J^r`^LhWVi4&*%f}Ct^M4#z$vs0 zuH{zY4B0xICEJ8A$hP4e*)I4!F*y854hrYV_Td8AAzUOohD&6p@Fm$9DX_jA^|fR+ z+yMVfOkJ1WhwIRL@y}4dTRx|rgIVys`k3^4wGQcX_nG@Xyba%ja`1Y+POp78yzW0Z z*PR^q8@Z0W19Q+d(tcL--O0yc_K4b?iQbroo{`g|o#9Y)wxv0%jn1@F(A05yZ?ZN|OD>On?G!B)?rf|D;1=L1;+>ct3 zEu!`uHG;>uzkL~$Maig(M?HufjM12HnA^9Q9`*1w63E4b)>od`}A$^^5Xpf6< z)(Oqvb$AU8a1zey;XOEeEBZR*z0q4gf!A>lI>PgM&Re**qvXxx%hBhjz6R#4ILrJz zzQCuEr^ti&03Tt0V{!cO^*JN*< zA+9ljOb_$6sLiWz1@1xtI4cI{cOnUQAQ{fwcA4|KZ$UgqZQhMS(WllG=(A+!pZ(Y; z3-t@+*Vu%OQGZKr!IyCRcBElnd+W5+<~F$B4^dyu{5NXvH64DTcINh$WdHQ`PpW|Xu zKFdX50lAmw+;3{rlt%p~Ra(c`52ewszf@2%P7 zoT&X?v-Z1g9qBr(iPUxJeH^9tUdp2){NCA1?uPGGX8652oZjc|^Y(qX621pL=)G32 z(QE&X^tx{)vyzig5!YcJdPUkl5q%$W4$OX0o3k+xGtoct@u+8!Zg;;`aJ~jJFc{Or zL*%qDjGPKHGuLOWs+fWEFdRfA-bY7QbJp@1DfF;JP>Maqt?w)iz6S6`Vn#& zMn}JvT!N>t9?mzwxyLL=Pdpv+@Y*Y=SHgM$-%Hl!F5J#6H*%pj^D*QtQJa04xvd9z z135A>wI4-)6La?+K<)lx;r$K4n8-n-+uhgNJY;$IPBfh8q2|1~A!2E&!|6|gu zqqnNMHHv|l7%1J+5(bEhsDy;lA>FN{0-|7`w3H&<-6`FmQi=j1AR!=#(jX`y;+^w; z>m9>C=6Ig9);{~Jz4zJgkL!0IK~sWt#~J5=yl{=2V;_RQ@#=%{4_AcRFfwg^yrbpLBoDqKysF~n5@~7Z;I2w8! z-3C9w0oW3H2z89Hei!V4-S9p94CZ{^czfV8<~BsU5nUUx{$|AgqIc7ivHq^;F*BMB z)GXoEq;M-_ha6xoADGVu1>jM59L!le&%BP!3Cr+mF325m!k0+Fcf+^5lrhQC73f7+ z0Dj;4ORxyef%R2z3-cK3Z^NsL!Et|uzmxn8ylcG!uH(&FzZzqF*5|B?-kNu^5OMmr zlX~xHR$|qAyPR=Ppx#T@F%9*1MsAMTW}@;Keg-Q3rVK&F-<8i%@%LybD*iqVL&e{%;pm9){=VspKvD1> zz6!3xd+9p9LtRTTC;|TNY(l>R&+1;jF@IOP6T9#3x94y>cm^Ga?bROb{W5Cbh2c3E z1#971m;qfwji*KY9y%4&55lWc;3Jp_ABIi}KN+>|xMg5|1x$b*Fh1yojtlyrV?lj2 zym3Vs10CTX=nS)<7E}nYz5=sh7|elA@Fu(!v_{)OQ>YHjgQ{ptu&%EJ^`H^7g4&^N z!aGOJz-Jt9Tn@@Z+3=;q_eJ}`P|){=&tVSO>sgCbsu&WDAt8qBW& z^FH$hybFti;^-1s3i>quE`?rA$+w3u1|^{z6oI1Q)%U^LJ5UPxhbH2I#4mzlyMyD0 zfa~iCpN4*nT6e78=d2m4=Jd})DSmfeKwm~nsPHwEB`zI&8M$vGzZuO)Z3DUy)WBxtUJ!Q2o!~Tz_E|QeW6*=`$5eTeiuD` z2YbL=X804|9@@e_@EflT2cQa6gV!R~pNhB%dIr>Ha4xh3`bNb1s}XlVeb3*}5pIIH zx8ZfL4|`|~7r|UZI0@!{jkrEqH)8!v_yy`fXK-HU%+K16p!v|95f{K`0QGUWM*ap| zhfASyN|lZ~~6P1u*CH#)ku+G515nyU`sH>mQ&G;|J07V60CE z_V@&(34JoWnhG9)bLbQ9ijcM|KsX5VJEOWje~ZMmFGj^Z`2rR9)89LB9~YwHUM@hz zy?GQLwpUt3;qCWU%--x z^~>O5{jR+x&?g?)Xm|q@ZTSkuveE* zbDN+AJWZbkVK=@U`~X)OWBeoZ4c&t_gV&)YGze{qo@IOuv=*Glt98IJ#`-Go8dQTy zP#?_sym9%!XUzS@bLRd;uYs|?8#&_-(0*X7?+y027kY;73$K0*AHqR61m=!|`2%nQ z_QP*r&RQFA?9XsN|68DX7>-1o@NYgsukZk422i_=eQt;Po%+4%J3vx=+o<2dnC^IE zeUH$t%;C7Vi1mHYcfqyxf-YdrdS`Hq&#Kl%Z*3drnt{1)7v8a%_*V2LwQumZzzzIX z)Lb&u{1)&xq5x(uU-;e;4@8~6Cphjy_&BsaS`XC6=q*1O>uaIc>CxQR__~k}zX|=D{P@VNLqCEZ zpkE8ULf4>uKwTYdh+JRvOZWs8t&PRE zMO(voe0$V*BK}R(cxw2`=yd29Ieiy=XP6y+CaU*$>0Kxa?tyzTHsTl2F`yO;ua1V2 zFanB)jtoBvweGliV15A%hf**sD1#0SUO_(x^}g`N55f>=LQnb8M(8F;fxp0=zX&Pu z=g?Ql>r;b1J6aQ!ocP+PHZNzYT7O=iwjr_g~PfFGQ^f zdIwYpO~jRnlYnDiLLFZnT;I!3HM9h3-LZO~vu3QC)BD@{ExHZ-ZPj<<_t$tJ@Aw3^ z;FCf!@Nb9f@Nb6eG(HTjU-fT{d!qWc$GuejyX79L{=J%xSNDVas-A#Fc=cCs-_@VM zb5i}g=h>52gTE`P|K{;`N&O!Dy;A-6)HuBAzo~Xbtlvc5_!_Lo zUqvs$I=uP^ti`JrVGUlr0ITupd02&4&%p+~dKs=ntY1mq_$;izt7l+2UOf%V@aicz z8L@r|d1HV3D}Z}l4$_hLw_*ag-~RsjZ?_@D4?+qUL*C~`!5hS_!1=a99q_yR9=gL$ z_=s_SGk!yUSAI|4$BxAAv-|E@cm~DbIGlwGa1P$$o2?6vht@%BN35>}Pex8(6AD6M zs1DUa3!$$;4Y2Mw<2RrUJPVGk3PnPzphZEg96kwpgT8K$TqQIoEP#1XAMS;E@DJmR z8$j96hG=%k1GykmXg2gtNCjyiX=pmsF~<6bASFBu4?spR=kvz*1wLc$UwSZiE8N5z z>z|MKMf8=3^`*fc8^Oz=jl-)Y;3a4dEx=q`Fy9Q?LsRGg=B(ud$F_t&dB55UUXM88 zlkndI()*jsnCH+dXaUCfE%;67pMXE``BCfFpcvj*Uo!L(-f>S6>&u|efom-V&wx4W zPlIE8R<$mAYk$Le{6)Ab#MjX-=nd!!oy~!{?qL2JJj*&dq6J+K+6j)pvQXonBVK_X z0(Dh*^&qT;pI~+9{_qD->yA4Q<}boNSPy%Hjp&}>EA&TDdxtmv1a`xtFaxqcB^UsA zKr$E%cfmd3KMOw|O&v@`(*~2#^pF|!)5Fh2bAa!f2eTsn0?i8GUL!eK1wFex79dH~L!W@_%OhaeGI2Z&Ig8t|vu&(b1 zBVjB|h2fzy!#l_4fzLSJxEJ(=p5Z?V|0TK!c7lEbdQ1qEGW3zlXjLOW|#JC%n2GtSx~LVM}Nt z{)YHnaO_HO{P*Dc*1`7BHK=vR>V3|dv1(55o%{#=8@!YH%cyY?dOe1}hW`M%!|UKW z{H<}F#;w5ht1ZDjQCom}sWu1qQ1y52_t2)O`>M8wOQG#h_g!rQo|D=bJUg`!c%EuQ zI2PIf{RPzeP%mQrk5CCJgZEjj0^W1AD(nlbhW-R_Qu;2Ee4l|r9J zt3Xw-?l|KX&rLo1*!fLcEM9{Sr4Nh4Pd%>}by2GoZ8pcd?9oN*m^CA2P@ z10I9ikU2CvdKaXIv~Wjgdekw-`V^1~9)SlT6PWXPj4Xontvg`vhjMf?T257Z^$ z)xEGBcEi%pAH(lKtvl`%m_GwQz)IK^tVVYRYtbE`b`Njd6TXLRFbT4P-*<0F26sX~ zxEt;b-#`3FG)*uXO&5$sGe8#5PYgdD%?ZBCdov~CxoAGf2=*`zQicvg9|raF@SmX% z!2_Tl47Feo9E3dJoU`B%41kZqtM9|luni8wY?uZ!g9+$V7y*4@RL~0@1J?CDUMh!aRpqb zaWioJYEy7e)F$w2Xk*kpR2#vu(1xh{sLq>yV?LeC$&C!c4|HFJk`43cc|8Z zL!q_NS`q7afOoPyc%Rh@uq(78`U9wyV0UO`)ZYfR3Y-aTg`NhrCF}{UitYuq8tey}xzFx4`}28t#KZFaQpM>qrJk;d|%_z2Op^iE}G~cfZ|t&%!hC z8!iO)X3zF--%B86D*g?L-heys>fi8h#QM9)8{dg0g}dR_@X1i0y9e$C=esTZ?Wl7n zL2shBM9us|V6699=esX>0DTbd2j7((QozIDbH2y1sluCc9>zDIGcI zcs1e@XgM(V68Mf6z7KIdFDz?@_B&RaQr zP1Jenz$@Sy^tHitskNXZG=TchGPEArC}MpJaIDYhou_H|R;bUt4sU?-H4EPyb?(N{ z5RCQK+d~sD=NzrUIn*}L4%&k6stX<9P4GG2}zZaA1X*9Xkcg^^%w3VZ_A-hr{u72bw< zFdC+Uz4ilZ_G+K2U^-Y|1m=ByEw~12<`%m|z1mj~@GR`t-i*!Lqp|(D=f?Kuo}05L&%>PkdLEvI{o1!@Vcl`=wSC&JXJOrb zJ&Uzq&9nFd%$r*WiFKLxJdDkI9mBEN{0@B9*zw}r=Kh5n@K^9a>i^}`yC7M_Nzq$Cy*0cwW9RVs%iwcYBX-{F zV63?A?!QRbP1beh*pY~|Yd^Z>Y@54Z73vIw$cQ9{mFm!;C z&;zV}3LW81_z1>8PcSzGI)l01VBTC8Fh3Uhg0;_~D_Cm<1Kic2r-ExU{sKnBbodNh-$HN=qhJQO25XDKHCQt@ z3tWe}rC{I2b6^-u1pDd_)+T`KY7L#>18{xzYmfG9e{CbSKlj|&e4=Oj^*rp=zB+-Ote%mZtl#bhvV zZayT|W#02JHt%`3CUeukwVGQ5o`w7F8a#`|;5y9B1lM713Ahep^PY#XdC$XjnVSoq zh5gyL>#;r_`aw&09XywI@K$L1@Qz8;KgRch4@3KeR~?r)+qdzaulf$W_n%nrIN#%U z;Iqb#7w0y29?rmtAW544<0ve@D*5F0p_iL4d$({1Zz8C3s^e< zyI~Eif}de4Y=R$QEm%7Y+rZj7FmK(y%v)a%*7m?{tigWG?~U9A^mg*cP}g?{{ueZ{ zu6_8+VBgjqXWy>*FR*WGzruB}ck3r%7g#?8=B>M~AK*0H1lM*D?AzK|us`$G?a$t= zdoG@_=W8$D!cp)n?AN~SYa`gVeR&R!wI|QPy8CU--rR3%_O}wu*|%q5&fe{7HQ2X( zZH7e8o`ZFJ_8hFc-}Ykd(XoBEvT{Uyab+w{kksC!si@o-;nt9K{nt9h_?H{mj&%r%+uU*sMVDIM6fjwHYPkXdxJ~{DyFtr%} z_XzqR+z$`KBai}8LaK<wy+*42!iop}`GL!5 ztt^xSYvrLr#1+v>5m!d5L|hfE7IAg-wTNq=wIa@s+E-n09reJqG=N6X7@9#7Xb9$; zLsO^^<{j4(-hfun2HHYvXb+v>P3Q~#;WOw0-Qhjx2L0fD=n6gI9ryrx!MiX7M!;a` z1B0Lkd;;cr!^bcHK7!FO0eog43~U@w?6HvbLm0N?E# z-@$g+1Bc*8_yP8Tg73||ATm#2lg|qNCT!%m4GFZO|=fPgg*^hJhjN?y(@Ae%&cLQ!s`@iS@#rv#% zB_U^TzUL8wBP*fx+Nhym!u5!Up;y6YM#D{TE}y#sx25B^4!y_k6*@u(cnijpp9Ev! z0Q>|$1m_~Bo`B;K|APJu>f!L#jGe>hcY@FT7_sy2jaYB}JUHeI{0_b&5$hfE2RLpu zOo0`!3YNom*aQn;KCFSM;JD4O5UfoD^VS!EdF#``+FDow*0#U~m<2Q78(0d9VI#~2 zYu~~$ur>$GTemOs*5`t?FW~~%ulcXQ+#$FKJHYi_g6|=*uCMV&!M?3K&c0pqF|coI zyWlslck6p#9a!H6=B>M~^{@|4gKOIg_HAuH*q?dp_Gh2gJr~c|^R<_i@Ev#-_G{nv zH4p6DzB~uV+LPyC-Tk&^Z|=7>`o?V3)4y_-7-_GryM?a`X~Yw#yrg@556xDK~-&y&DSy!SpS-n)MT zpA7vAO^c?7tZ*kh2=~FgkOq>&J@5$J1@}WrxEmgYT#y-3Lne3_(t){DkODHmL+}_p z4nC6+vV%3>p9kzA3*-dn$_vlIli=9=kPotfIiJZ51;A&Dz)SE9n0poqgYUFv-Z=_^ z^Sl5rLs57-)LKC(4!+wtUIgbU302?~ux_j`2BpDqC7=x0M^&f^m7pwC1joG!<{VcF z%7cB>hPu!gDnNCxRt~KBZs({4HJ|~sf)-%T*nAym2)^4n>O(zf4sD+(a7BTz~isd~OiUn~onrzx&oCGZ&NUfkfVFWj6|6bOEO4HQFddw0HY@<2nFe#g zXQsd+@EON0g!wQBR)RHi%fS2>upFGrIhMi_Ft-^tfVp*GeldIv&gC2%;koqu)}h;B zJ$wn@KoRn*(H-y=JVX26*OZ($4UffpEi2>k=jz)x@j_QGzs z07u{eoQKnJ5&nc*c=jB69Zta|_y^9yNw@;P!M~71<_F`PP#`oH`Z%b$;fc^Z;R~YH%g_TwhZ9fGQygS|MP3nOvIT%p9NiqN>==O z^gc8j+zV+SEtqp3%~?wh_e1KyagMQG3hoJBM(+m4TQmOv_?*wnLtyS?4fL+x4#zP{y!hSDB2QQf!=d)y=|d%sL$!0OaD4p zcP_p7ZtMCtpboSK$2h-vy*0R88__g%??JJCJljLqAV=VRXU+DlD;7aYVJ z>peTwv4_YRdxk&bRnKuh-uM7G<|jzZq2CA2r`m()?RQJ4v0mK_K6e;41z)4)9i#s$ zaF5KnU*<-FdpI0Ehtr{b(cj@U`t@7t1RsOmoUy(m^Z;XhZ>Ub)=TE{Za86^r&pNNQ z&tM4j2kXXtpdXm~1crirCHngmpBSqj49=kr3O^7X0M4N%<{5z>2BSgm+Q)>B3a^fZ zaiPZUlW}6qEc{Av9-r6yetUI(zbVgZEBO9Juq6Ca)P7_cxK?X=Ybzr5nS~MSUE3UR zZN~b!@I}OWbM`V5>`^tI3f7G0MLZ?car*h8)6fN=PKOy0>+Q#QRe0a+SXm6tA$s5A zyt83)pq~`zCxSX5{P^(pWX^r}+ZDfSzwaa9x4s{ahI)^j%bN3dfS%y@DAoAp%(aJJ zpsz}<3Ygo7Zun2U2>&Me60iVY94!eA@b%#>{9<%r)QS(w%W z^Eq#OuqS)9_6n2@weI`-fp@ESsLwclIkW@E*vl%sefUi|#^IUpaCWsh11yxaClZob#xa!EacfsQJCD25ah?h#L|oyx*1I*sJ91!}6Qc1&yILGz>L1Z%%cb)B|(%!Li1TB5r_6 zlgKp<-vZUQgl0i2v^l&UYTPE`H_&zw>oMSd9S zp3Fk0p;KTtyh;2cDsSQcL8T-9CMuoq|AxMe?*g5{F+Ni))VW>))qnpvwjewKj(;j* zwK$Xj$2HVLNE`dSd*|de$Fpzivcz$Ys@LbhTz_V8Sh3|_dz6pIF@cUAGgWs3h z3;ZtCp5V8t_6Ywm>US(3;r+h--u2x<{~_vq@NViq0Pm>!K6rQ4_rTv1wHuVit6iZ4 zUVS&b`VI_%w2&tFEOM#Q2Vihu-kfJV9QC`G5qQ6Izj?jii{H083jF5P(J%oTLlYPW zjUqPR6ehux@XgTapf(4;KjRrN7RH13#Cax0>^zercCM)rJEzYZ`+fUf=a>o8iTz%E z|7@58`nlk{Wgggrefx~#8iH$aF2D83;I}^sbq-^3ta;J=^6nn(*0B z>&DKL9~rT%WjZ>#ozh>wgsdzk9Nxxx?o{bAkU&!JOXz z{@{Oa$Pqp#s?Pu!;T39+Lq2!{o{iYtGmsUY2J?mCNpPIc>DBz<)u+Nc)^P4TC(HD|`kko$Rr30~B40aV^Ln)oR0^$# z)>h^ge6+JowJM;Qpw_`fN}jynAMxB{UH~O6(YU41E5s@YXVe>T~)#!MfyzJdg>J zfwemzBV-7l9!(0jgFapOwCGQq^*+$20exz8FY0{G@0@z)%?Zw>8tV@*HhZY=*iS5a z=l>m?*Ex-UgT$B7)!j5y)# z!M=`x&lu|+_Y3&kkEr8~)uZrh#CpeDI}RxszZ>O-&tuRa+5 z0rY!vazFk%RFdPjqjDeqTU74L%>O-#%Dv>bp>hv?E4n58-NgDq;NR;@q5f?#{|7i; z^?Ch8a9-mJ;QNfvgMAp=oBmv2-{#JOYcqDe`ZM8Aqwa_59_iI1kk~uDds~#gy$9Zh z7ef8cUj)_f@}*F}k7A(ujrdI%>q|uJ_i>1MJ!{YFXGr9d#5m)_QS+Sj_F_+Z$N8N8 zCj1Mh!aK%w{S!IYd?Rx1$=_hk{kjh3+|O%ZPJacif_wf~#Gb{U5qn0LBOZ-&F`4MlkU0RoO^x`-kf`WFW#JcejnbPdz>6^ z?g7-ec;LQ2NY36KLQA6dmLhTwqsI1RKgRkt=p$e(kAu%h0dOwK56-XpZoQfh?hmy$ zeRjwN*&sLMfILA?^f7R)de`q-6FKM5yJnwF4bGJpoWt53;G9XpIowO<@$Zb@y1pFV zzbk5;@YPZOZu$451{mx88)K}m5^-HrtW|^xP!Gz7Ib>zEd3RKwcdU2FG1m3oqol;*J@O9CfR>Cm=U9C!a9(4* z?|K95$@~)$+pGDEkyDLbm$gjbn$^tUKB!s1oZ~ZqIW;|4Q`3R_r=|^ljGXE|Th~7t zar^M*^t+)0cvg-vr+Kax>ya(MI-n?tw2YUD5CrIS<`@y>EbB=imtm)muf}u}_w{Ff@uRa~>+38z=XWcw} zGt{#dz2~etK5^!S@jm+u=$l4d3iUl|>F|Zn7r?&NGEf%GJI2_&YjVtskk}jbC2-Ho z`&?x(XRMcEV6GArkJx#w`Ao&|RZ*!Bx$Okfz6z?nxemu0JI>m3P$bm)v)~@6 z#tp)|H||RlXbkS5-rOm0->- zXCrW|&p5_PGC?I^oUfOM=g-wV}j+V)xIzv}RuK{=46+!87q}tgQia)xw+8 zZ-lMk&H0WK@ETMHdoVWt8`xL9;P=QGyFT}71$+m~VP$x8tHPVJkL{8BHsWtkdsMBj zgY~d2*n(Qy9BRA^et@0eJA9`((OXmJg;(c>SA8xq#-6R)muhTp--Edw;JY`0@3yx@ ztp6G|gc^StvHL65+-GrZYr%1PYsRkMy8Cz%++V-Jqx{>-ctYfjYlg3d>OC9B*8tDU z*fq|FIpCV~iJY-(b3F^d^?eoIwfq{f>kz*MzX|i|@z7)8eeW+|Y)^Xo`U0FkG512e zeas3qwm);Tg9DK}i0Ti)yP;jtnV_22`<(OXXMi>1r4cU*@4J@3QCJN2rni1LytyM_ z-P&ZZHYwD)d*J$At9f-|c-O9X{Zqi_hr%*&PIF>zI+$0d!Bnt6b3W(Xj_U^2-V5*g zT&MfvzI22n@D}{b-%I~ys&9vHg8Dbrx??*9ol$c=Bev#z#(Lk=BVv2_IO6xi+s_B# z&3yI?(NADQ(j&pCugE{wmT*TfDy?4d` zooVcUYWguS8hlpo9@yL4!QK2@%iK-&OEvx{_RgI9+8NwiX$tPI+6kJ0{XstfoLdHhy~rT2KN$?~1om&v*tNPoz58J7*fWv) zCt~Nile+3V+%LzRg>w<>uZB0LSFgeOP~#imSfAJ5gumf>_mGFO|_Gypi{3eXAqsG@FK8xzlf!=YBQU3~oD|`#o@khb@39x4TX84w<m)13ZyI2LOCA~>&VY)_8c6X+d(9DMd<;P^j4_5FI!NN-Pi&+206 zZQ<2Rj4}WJ&pS4rzlUh0%$65241A*_hkAtE1C7UDX^KXFfbH3IQ zw+Y`Cm2P0pG5SRA{m6e1d3*d2RD0>yH`bdQ z7_s99f%-|H_x&G1FX#?~!FuoT);# z1f2%H$9b(CfiGc3#CpdWe-6&&J00iQsm5Q0{~DbMK4;EnjEBOo(BY_-$o*Jw|{omHq)&KF2ku!Gek6>MO-tWUd$r#6V0sp4@H(edT z@0)+q6S05e{X6Kh_G9cg$2gbIJC}d^towWEzNqe#In~&)KI2@Y@YBHm)}>edZ(kE( zI1CG~E(8DfPXB*7694}njqr`(5o-4{_XD7IBlj@+UT7jt)DyK7jCl~$hroIMKMs8m zO##`m@HdirXXpZHAvL@U-KZI7g!Ga75X~I9o@i5O485Uw#C_53JZr4~1YQsQBrCs@ zc<1oBhM~qEMqC%o3bi5Ie|$}R4k!Y};KlIIq9vd(yd1s|S|;KOXf>z;<>0l5UqPMI zI4|UZ$3t_WPlD<@ozL;kndn0`&IhAm6cm7WvivXBKLP9EsZismVFMHlHGU>|4jl*2 z!}#zopc5i~37r^maddLTrO|azGSs~Fval9P!K*MSVtsj-5?T?R3TkDT2328t`0D74 zh-;uTBd&$cirDp!gxoL!a)uv{W{-Fn`e?*M(JT?yLAz%8-(2sa=0Ar9Fb8JC5cmx0 zg?@@=g29j>{2(-4#A(70LIVgZ^141TTZR3gA7i1m&O_nDcJF2IlgD z_c%Y~0q?PKE^sbm-(MzT@9!vh3<|(#FsEM+V_*Y317kzSh4-H7pMw`*JeYe4CV;u( zFcHkH1LKn59b5}#!%smcL3x-8#uZ^&#NJ1}_p>@o2Xi%G2AHb_Gr^o|$_=h-MEH^D zaL5_CVQBWq4MiUXb9G=AIG^`03t0DCn+?{zkM$r6dQmzn zpvGzO2T|k0_}d|A=-cRRK_~Rq;4So)paYsDXovpGJU2oA1pI?n+rZ=SD{(>e25Ro_ zh)}8Cnl*4r)Va8rm2w1Rl*`{*~9AH0v=OZ`#QI4}MPYMck}ecTM*N$;cgQty2<&Vlzn zz6p2Wy^m_*PJTsvH?j9oy%&;$_fr1=q=1y*eM}AB!L8u^Gxk2(yKC@19s=*A=o5ER z^-hZS(YxuL)OP^yr0PBNK6)?p-bdpn@a~O!>-p_AQ@1*zBeBw^3i94w# z?xgCS^qciw>YoPZNZd&^aVOQpom9P(-be4H-ur0mo%B8$C+?>AGI1x>GSs}A=b${k zY{ajk#^w`uRZZMgHE~x}@2dCG`>OYz*2J4rjq9Mb!8=DR=v+Y@7%9|_gO6m)uG0Jdhp=YywlPVQU%+1 zwlm&)t#$$Lbw)@B1F~{Y(c^Fe`am!EU8ouNhklVeiw=z3C3F|;fIne(#8=SMJZr4K z2Kz!Yp!>l&eD1qYW9K&B27_S>eD)u|3I93Fg!wQx{B(37OocDPPePYOyc*pI>tQ8) z74dS^IgLlb2pAVS44nX~?{q%LJ7=N~)p#u2&3f;G@%ZDYv3?@t!%q%1o(B2JO$jxg z5zIpGqc#Ukj_T*(??;Un;2%JZ7vUd5jhEr`qKiY#TVDZ>;g_PT;6c2xehs9+tLxxl zyt)A%!GDRSMD<_eQ=!J2@u^Yct@t#kvFpDRMv_a04oCHO;D@5dN%2Ea9A z31a8^HS)Ki-;+;=riEMK7T8WsO#*}P|H1&!--J&h?i>Ce^ak_>bAQ7?o;B_f-rR5S zD?Cc=6l8;w#HT^cPJ9tP4`<*4T~1IMVtq{PVOq~;4WrHjemx$)P4%h zg5QhJjGhUf3C##Ul2Fy~$N9oB@ugn{dPyA-dXRi zIek9-J&+$}5Z@c>z0}Vkr}y4^Prak&7JzruocGW>YR)@qycoQL-o+K+y^G#Y@1u9o z*!$@HGxk2}y`Nu$chTHt@GhF$3f@I?uF3o7y1b8i@2B_CyJ*h)=v_4DeH?-}=Y8}p zI-mFOQ`EZOns?E<_i;OF&HFeAHTFL0y`MMH0g>|_egfvakA1>bp5C%uE- zKXcx}AMnQB!JVkFcTn%0^bY=tKL)FLS1;l|P!UEz1t=eW7+Mb0&*9b3S5Wy3%0ij& zgVCPMs}6z!@Fu(zbVQ28AJ8Vj zPP8#J0{!>k^HpF{P!*jLR70l))zKL+3-qtSoX{HRd{AqKe*s+xFTyfd5?UKw5!69f z1$EK2K|ORmYy^D+C>pW;8+ab-hi`~(4_uq;+6{~0YuFXK72N^qHux^|TXX?Tg?Yhr zbZ#&coej>l6uu0WqZ?oy=vRhcjjn--U>|$J??cDKXwZ*={SoUsK!5lY-U=Op4uvNo z*9jdCZwDjM_kx3HcThhLe*}Fx;-2U)&>PzD-Kxgk$I_^GvLg7+jR5bX_flUj;$f)w z(fD)lK0XEBN$+FX@ZLw`!B7BxAx_*$wIdXRC!sSG5AA|>g%Y5D2fD$B@Bw@TFGC^l zJ{o%;?cFtaA6v(rY)7m=hI%K}qrqX+yV)A_hrm0j9)MQhz0`XjjmLs};~se@p9Ak> z3-EqE3zeZcnBNP{LVrZPlj;x9By=a*2pWTa0ysw%m=szS^-ikQU|MK()cfeY)X$0d zHFSQ&HNw|K6L(Tw1TR7@SO#B2yd+}twP8hQ9ds3_bzyC2J#-_i2Ypfa3e2g-n_&|? z4_m?dovjpgLhLk-UZgYi#sCTih7rgz1NO+>{ReRtJA^ztj+|V zch05oW$1Er9c+MvUx{B06Tvxsw|)=ogV8WP{77^^yccS0y#pNK`|ppw74fIx3!+1z zQ|NH?ZBTtaG1o!7{0tul&!9)3XXr1e_qre28;*njR=WrFzY+M~2O1E+0|oG7zD!Q3tAdGrr>1b-2I7|j70;a0F;>-K5C1;JV-$OArS{%J6mSXU~1-iTepGhog& z6##Qt;aSKBt}QJ*2akg5dK}ETj_1Lg>o9f=PeyFNFGMZ_`V{1Z6kvbWT~}_n%sP^x zH&NGSzxM4K+;@94=Q-G;IeRv5>^a!C{kre==ULdBeVemC^X5Ek@FnPoAVsZyDrbcS}w3(dvr~ngX12AORVPtcrG{KuRwnt z9AnLK_u%h>`vU#_fnyx&xq7}yg4@yCz?|N^V;$!^eBPQl)!2F8hBnYC)VNRZA^H)R z>jLiw`fgy|ntA8&xi_F4B<6cFyg6%*`2>1_bN2vqdUKAkJ^*UKYw#jegO*Sg8bKL& z6>5U@m!L72D+k5En)&iz&3s9y1=cG-6R=(vio?s$94bL&s0ZdsK?^Wf1xkZ8^Y&!T z{3}o&toH-+_T3QP0c!)nwY7%+V7(Q%u6LmU*t>Pd+53B7-QL@R_3mKJHM|AZ>OfPl zX5MvmfZEU-nt|)H_l{uQ9<7T6ZvS-Lo)n-8Fp-*6rOr_dI$- zPjGGa-5IRepM6@lKl9ed!2}oq!(lKC0rQ{3Fc=A+!XOv}L*X-+15;rNOoY+kSmUwa z*zqt5oO?0M1)rM^lfe2su!m_d6DEW6t%U`!6db<@W<@*$^|^&G8+`67SOcrU{3`eY ze6RT>une4MK5T}Kur64MTHgfA!S`S8%McV-CYPu!j@y7hHu4;eSW1Uj*NK5}fBxI16`Yz_B;LF_+;A z`~miI599tu9s4ibOMD;P0m0O`#@KgV&)B)P_pX z45~vb=mxE!Jv4^~@IEw#w$KFLh8FN1bcYVm1G+#*=m%ZlUHAYxLp%5sdc()?IrN9V zFbI0WhcFC2f`KpwhJs^zt!u2uy%VD5J~ z7wFG`b!+CG!{-jbVMxsPOL%kE9P>B)1p9!Ue(*fL0{gXZd$QlRcAYH`f z^G2KjEebD3Es)0Gz z)ey|N4rABwTEzC-IC90%8t^I<2K%$_y2?Xpcnq?FYqMYbb`73`J(}|z?9rS(n>Y3x z?Av}l2mA9Z?9IN-*`IlHox5>bP29 z&b{|6%vX%qHPnfm=V0EP=V0FTcn;QFm*-%u3fQ}Q-vC^LdvENzsz>Y^8b!`?FmKLt zFz>oN2W#cPe(ljUc@B;%1gYR*@LV!O+CZNX9AnLK1t1?h5$K-^9OGEe)$`33EbBy(c&=uZ=CeQ`?!`sjkT0=YN2G*NGFEH00nt?U*9l)CTmhc`}e+znp z^$(#rw1R%n5jsJ4F!wrq0_Hly8(_`6Jy|o~20jAo^T51)_kgirZ4tP(!LR_V4*=IS z4n78Zx9&K5p9t3N{WGvW6|A|2;b83p=mXZwyRM<|KFo%`;QH)+1X#C6Yv%3Intjdz z&)0LdkAdKMyaV=Y-}Yp`t-+og=XuzdHP53N*qe3t+P+?=z7yfiS#!+4a2=fc8kp0YbBy&{a`5jdbQ^pDTj3yV zh96-ytb=dC`eN7v=GMa!ux5S(STnyIwuALAVJ}$U0ZU;8?1!)5YuE|qR>A==w+U8( zHS_jl&HNhJ1=er=9~0*tzt#Ny@km7qZQ7!xw6*s#DwWX?DQPchX{Ukq7VTZAw3qgl zw6&Bb5+XAV{hrV7@A^C*{&+r~uj_ih&$-Vz_kG=k`vL5G-ACYOaP7{xx3lC#WYx+z8_w<&)oOJ>;4^F^SUpBYd&xLuKQltcinsX8(jC=edfL&H{cq0Z(jG0 z;F{Oxb-M2L*>^n|*OmhAfqNk}+!r||cKt3$1!*Azq=$5HH{1_NARnZG{O}Mw2=2`U zSs-hW5xbrZGK1?6Lw2zD2;=~JIpI;Tmm6|{y}XbI?D@KnfjzIOz(f3f2_7eVFUg@i zRD_aH0t!J1)(fF0Y#uDRD-He3Ce(b-DAHTRDjapx!wOF)B^j@KxKFq zyoT!VG*ki4*BI(RJ*W-te=_Q)u*cPf8sKrS!z=JI*lz^S!wX>F*RBuGf#-V_+Q4g( zU&5}pfCk{}HwDkr5V}Dt=m739H-XmB4BXoenuFKU1^Pf&=mc%Sz4qIKdpm;H&=UGW ze|QVJ!<*o`{WrkZ_dLCzGrSGMU|?kXJzx;{y1l{k41k_63WmbF;GPjMIBNIwgOT7h zyaVsU2QWJFd)W0c;Oh>7@!)xe!yK3oAH#<*4%|BhCV+drhDk6MK7q;L-s!Lq7QsAN z3=61|Jio6y6+Ctc%z&lfu`^)>%muH}*IEX%!2SkU39G^Wr?3$` z&noadpTTmlzZurR7O=k-*250)T$^AWc)q=0e>>RU16yGqc%Gf`Icx*ZcLcr!kJ}IK z-vviuH+Y=;55pJm4IBX1Pk{Y{a0^%eSuK>?MHSl~MTLUV>lTZuX`z+K2&*A4Y33%+2jHEtWV`HQIAdF2N7bH@u7cH{XZ*;{l+p2jhWoKUv--+tWY65EvHuXFLM*6&Mx% z1&;xJ72bz&kdpI>YxX~Y36O%`r0}oU{2NROe#g^-Kky8g1?E3tPWUf85A@%#Abbt` z4Bmq8;k(G)@VB75z{T*J_yXuR;A8llYy2nb-Q@G+#bEC`oP&jMHt2xQz&BuS2dBer zu(X0x@O9)C_$25zd5zbjHt!_giMQj#_)FML-UD|;`5+u4 z-xEGTzL%^|@cG|>*T5b0WED9PzK!?e75HD!w}NH(X0Qa`0H2H5=kx%_dF|eVbKRW0 z4R(aB_tI~PcY$;Ld1U9$Z0{gge+oyUUWyNJ>~efGSczA|@$fp_9zKCZfw?2hhmZb~ zJCQrXdoUE7XY)uH4TIpF$j+bjSa6o7g7f@g)HAWOY3)4sfL_oCx`z|yS$jTTTaO3l zwzw{bem5{XtHWSO6&Mq>v+8V)i{2#s0VK@kujJog zO89r|OzJOkJ;YZ-b z@T0gs=$z0noC`OCSK&2y8D4?h&@3?Lf#%`7xFzVv;BmgQp2yDxb@5KnbzpnAHr@*Q zS=bz|g*QS?=pVTTULSQI{5BMYXW(gY&E7yL2KJtUb>S!R8qn2YRk#{n0aamHWX~}e zo(R8-i-R5lCBnmSNf-g8B9FqQqaKUPL~R}q4?_<4044=fa5>P^pnP~Ht^j&ARD`)u zIdb;M_7+1W$QF4Ct^(To^8QxC0+~=#elSJl{O{ zFgyoOhFLK6KY0duIt+rf;I)_sz-Q1G`bFLl+1?A#1v)}K=oWQq{8scD;Fq9hxGC-p z`gPb8m|H*w*cQ1JZUZ|YAD>%oodsIMV^9QoK_4g-xiBsWJ)-A4c8{L(m^NzX(YbU! zoyX4DUMg@Fx6*qA*N^&9oF?j=xDhmj#*uU3SD+a*3FpDhAuptl+!A~3-h=b_9L^iw z8M!Xr4%S;E*TJ=6bM&0cjZr&~X6Ms+><{*QE=9rT%jG=U`^D{ z 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

    iH9YtLvFskB{yNt7N~I#@rj( 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 k>#8~Y

    s_VSI@1odc&fi<=jBR zs-m3*+hT&|>6*GRoK1V2#(o95_Kcqu7zioLwkTr9e(dx4J?7u^{haTSaoF8NuXt1u zy}G*Mok#o}El^Uv%61a5m~c}B!Mp(!QTK$|+cTo_Sp!wVrh!vLm55fVjWuZOQ0U$>`CjDQ^>O&7@Q3dwHKw|>(`mch zVWwsLnzv40pJ=LrCIOmUkG1A*SSh$vHZqfPAh6lm&eW*RHtgGBSm(x+mD8>%lK3)d5biv&JZY~{6ZvQm*^{d#5-kKkL4fOSzVI)x1m_St-@<`|9T z&~tl9$MR~%yAEG?5ZImJRVJf9(qZ}APW)cl{rva*8oK^5+g4s#pY0DY#_bYZ~Pt?u!zY2IMpaPy6=R(lau^| z*i{>2=!5Oa)CZ0us;;0o(KG*^%>5{uiVHn_;Amr5Sj-p@2rA3MAFJ%Bv4@!M=?y=n zOipt#U15i2EF1n_|MOi`lCQa*$;dG{&IxkD5F918-)DTs!dc`L*PCLMoLZDWKCscw z_Ex@=V`qE+?nwE?{w!?|A$WDrRA~+-;&b!*0?@K*$k< zcpn7~AoOD%I6eHCpO>R>_ZcX5fR>U^BF+47geGXa_pgD*3(nozGUPHE;S^yR@Z-GQ z5J<3hVhA%{gTCTDeJEr&szNmv8)!6Y)hBYU?LX*@IW{j5%ugEbTK^&m0@OdnnLBp zimr<;%8NN#>jwtB-On1mv&q30ua!zy{oY|J@xW2tisKCfO-rWcUmsU=?D7r)*774W z>~5Bi36&4LmF$Dd4~76D3~nzL2xabIe0D{S{^4F`a_d!2G2v*w)xfutM?q4-?@yiC z=+-~O)ya?NKqb09Jo)t`6DVGkunro(|MQ>G317z$kvL?!0mEvrg@U&$prbO%mAyJ{ zK~~w!!vp0}(FtP*@l0@)@xaklnM18=gLE-p$%!vpFnautK4i$WPCY%E%OZhKH~T`` zz$}kTa`Xhr#U}hyHb39j0CIil8vdDBma#9Jgc5T^vMh~5bVi+1hy70Bf}`K*no|wJ30!W))p%U?;jRu9*DZY*XpQL83jV zh?F3WQ$;|x{S0u&;X@3I)Z|l+6OvVN;3ry6?TA^-=sS&P^Xl{b3mF~uFJIoyF%b08 zG51f}5zc+i85_*=ni28m>4P_ku9wW%>ZOqqjw8F(bQ_}c5|#ruKi)JN$3c!&vRnLF zY$g!hSmTDt58WfhcB&i&4bo0!pYwi>*Z4l*aK|&>_?1h#(b zxz>)dYMykhc=&>w^(E>41({nyOw^?KE?eZ^S%O{nB{7&;X~glj~cH~7nq99wg(Ht0iG;;Jl;$MDEhURwvjxqLxDJ`sxiTe=2r1b+RcuLiB) zo?&Jj^}guY+e*JLvvU`+6tot?FMRV#T>t4&^L={zg$2%@bdcV+Ro7AK+JCp2^x}e-g>>pVJ2$P_pUdzgmDfz z-OAbiUwWL;Kc|o?ia88&3%2|7q(r)3Ax={~bf+A5HeFfMW>7f&w@v_X)0aXbf@jrkJSy zKnM7TsgPJ>vH3EI8+IDsd7S@{6J;PET9B86z1%_9H6%(b zyhqKaPodDuN-G6Y^h0(7-A;mFM2ahlx5ZMJ5Xdjk4dkfmA&w6=95zWcqa^g0 z#n~yUCRt=KVkdJsQtBR93$;wK#HfJ&MvKmpnI*dzm@xHES)59}cX4jZNtXL9;tK~3 z&rpK0y1ODTO+F;PL#e3^-|hi^4Pk!q+?Kz~i9v~BA0w0&Iz04^06tsCM<)gx@i%dM z)%T^1qtKf;2Gj*;XA>_NGA;J988EoLtMf9uFI)Rj#GJLAhU(8S`Io*8O0hW(^N@a3 z?REq!r`X7X{WbUC2(EkK;Un}8N97@E|GK&@n&ci zhc}m%3*T_o+>5%wnf_%F^;Ku(50&>M&i~I9{TPtsec=%G$13JOpn#Y`CRoV`-#DQX z7o!|ofN$g}atnrNpd2yOTKOLODl#y7?m3MVkKI0zj z3neH9tDU(zG&kWUnFnTel$IV2Q~pl214v)NTU_;I$uIyjIsKrnm-GB&s>S+frjE4; z;{=%tlAsUd(+i_>RklK1`#%@gsNTwbF;b4w8;DxBSt6&-23-ygLlUzK!>vXzx;etW zkN74hzgY3&2_pDlJNGaa_*&sWxi?&?&n-bxe?b(MmW^Pb0sUSu4NfmM^zT(v8YvGR zbSyQ|29;1Z=0hG*;>4@*CRYyGTb?B6bkjAbDKh8Bxg3ZvcW7c~l`~AJLi6jBI_>zGUx(GYw~rVGkaC#~kC%c^|2Nmz zoBjtx9a%~T8_^CZ#b|*KBEt9NEv+RE8e>*Db$^vT!@Bb(9!19l2g!7yFFh;w?o`p_ zvv<#ogNP@|9y=D;2WcrQm>AAvYWl`1xg;jY#X7?4N3Qa%$^j8{a~HDfEoR&0N39@L zylft_9)DP^K6AXMlD=E^<2*l~m#xlNxlT&T*OE3omP7jz3?qV4H^ptpnimbPm)(H+ z+SU$42E8e*Pd@petW~}*3k8s(eG6CIMuXH(zD>IO=DIw9KE~DHv~xWTdjW~pK!sw; zC6@5QO?qV$e!Z6teS4ReLkC<9ou=<4K@(}FDAuQnZD^K}a_!6-UX4EeK-E*DlPL)h zK>(sX;pWhL;|YYEU(xCXh66S8{eRzn+FGPN@9D7hF=xm(z~~mYi&T7{wt(xYQ1nB# zuYN3fi-G`Rm)?+a7b$Iuo3}5CN{agidnFRI=3r5)(0y`x00>U7!XZiaNhkAgxmGW{ z?)|n^O&Mfg)Q(vAbT=T$M=Q+QQz!7_jFaJs0OB7%Z7Mg}A|I{K;*Ziv88S5!3=<|% z#j!9)loa9OWX{jZg4!bT2jfM-3;3J;i0N8tW+%X1RkW$%I)=WKbw49?-N`%37%di; z*olm`mF|O*tM-);iV@3HUnkWi(F-%!7AqoRpRxZT38u9C5~x{A9eBkwfZ=*%DrOeP zjgo9LdB>({4fvwWL~Y(!uF7+W>wRwIt8kElFr6+xWF|!sRNwNs_`)%qYXgv7+!?ZX zD#)u3)*Xs&vVhh{$KD^i5{Q6P8{7#n>*#`#6ms@O8g0tP%8j{i7}U)z$6LF;F)n_-NM)I=&Z+IPQurPuT^FXS zA3E_(wg1{a^MouwD$Gs~sv6E)lo)t8WC%k?GU_){7jltAdAv1FB>GH~K^#%+&Wc)| zhsgZCn*0r}M0qO{i@JgP=HZwATHKwr9aw}UslJJY_j(pWmp2OC`mb1tptSm#I`p%ZthcuTGK)>pybG1ZS@t;Z9&F;5$jQm}@A`DnA1Z4>hWgaha7x^C0R}o}HES0C+|wb5_>By3h;bZ8I2js~_-ZvM>Z*m= zla|&#Tlu8vl>P=E?X*@ndDJtFE@8V{U8$0(#XZTa>!s ztr9KqIfuyW)O|HN8ia=|=`Q7Ig8zBLL#UTS z>-nwI`R1(_P*(HM_{23w%X*;Tqs}TDA|Zt3JF$m=jm{76KiOR^$%bv+Mdj;@gg3+9 ziB_7I@O4mr$OO)1C1D7rGCwK<)_wb?^TNS|J|^zuh@WWR36YQ zRr9E1J(^0Ap>>DSx9~2{(oy>{6}UVnhAPze&3WCM03_KE5WLL_m8%Zk?{oUl)k?b< z*22@ovu70*Rr(MyLBY(yu+UEJuhrF!2nI?g)S+N%jK}poMJhWT?~0GvHkW#slQ7bb z$z;a{%eu~N;JOge5!F@+jyS|}+Ry-TW?J#Svs`(j2>0C-9hG$KAdAhHb|;U&C3$!K zAuYVvfO9v_^=Y7rbyfxxs+0UF4N_aF@SGpv4(ctT3D)CJe%e_N(tpuEWS@Pb97hO~ zu?uvuOQUo!e@IGwKqiF7MO8m&(Ezk5Lz?3Ow!S>_o|i=B+0<{P5aBtz00OZm^7zVI zAD6PywufOX53#%)ba!s$<#+T2y8-4OU{U;Qe!LC%*tyZmNpAafR>L;bOyPrx6Wu>V z9E9d7D+ld7)W511trVIyL2Y`g;oQW<#XAw2B5fzWXg~_xQd1$g;V8zyvi9z7RTdTZ zuUX})MFCmi*=Id7J5vf4x791F5RKcb(6vZ|{VRXHwDO;%+t8!h)YVYCIZ6ln&E;l; zYj@j_yG+J6$Pjd%LJQOxNN+g9&(dgp?N<>Cn&!p|K{WhKQ`)|@a2SxRUlYQDTO5yh zW6A%lL5QpIA7BBvE}UCsQ!OJZMidDmcJrU~;C z^~<+GE_;f*fMY&}%{V?1OWV zvqIZR^ONuRP8hp$X#4;+g2ksl5s6$JKAp>=wU7W?Lnc~OjK@dnQrj5&>`Xs3QAGqU zR)u{U{!Km!xB=-OGA=JjsO-l8yh|(= z{+3q~WyC9LvmqKtpF=s#Q*ub;&e9XnE^j<;NYH@2Mo~~lg?gNQv{)U%+^a}9A!yng z$X#s2eJon;*^z?S;<<9cm^-vFa{f3XZai_t{h?3|*CS7ZAH2cFP0H6Uz%F!2w;9Y+RBj=ulXz3eVVS7N5GQ?;dh%`7r42oA^k2y@=A> zxMf&Q;m>E26M-(@Qg@}Znh08R4W|xDcPoAW_R;)jMtmeLz*qKQQEUWxdm#bixGLW2w^1o^dUwq39wx1Bdull@N@szFTl zV#u!?d7PLMQMESguY(uMe5}2_iEoV!Vw*%Aoi(?ueirbi4_`HupP1Up<%citOs9><#smRbaQoswxr99iW>r)3vH{`)8#|g zPnUgK&W}$IvRSyQBUd)5y5^qB$t94^yV$w5s_CTGo1yK|yC(S;A;Fwjvbd_8UVh+^eDhC&BXs2ji{vZvvl=FPY=C(B*;He@3TS$Ax5rK#(aKITR4+Dtdf9;=FOHp z7dJmUxfD1sQ!7;VQ-5=y4a0_rBaBY)k`*;n+!x-(g42KXBlmD!BF4M&A#3*AOzh7+ z)lT2HEM1H2m;-Q;^ppdxjAswc3c=niaU<0-@;tugyX22)x`+Rr;ShTxv03pS;HMtC zWRhu$KL77{p(=6lp^*l4a+CCA!EHKP?Rm>z##o#-(v#(&aI=<}HTXd_>Ry0^43s-Y z7FSEQt=PXL-{&Ps8G=JTwUmu&fACU0rL>sEeKmwIx_=l{xF^!z_w&j--6zMaNuz2~ z4UYamL|I@jpIS(O(0*&;rgv;P{y^$=;ck6lsl;aK$5S0MBR*M{>P@^EVZ7(@1dC+7 zFK&@;2!SsfV8P`uAD3Qlp|-OvHth22XHB$~mN!D`np96d#){i|2{F+3(mAo`jq#o0 zeH~ZsCCj|7#>cS&P(Y8%x&4``dOM7XtXxJOOt#I9tFAK!i`bH3p>`>6=J`23I!+3x z1M}*7ZqLNS_-qT;Y!yzVq$i?faHvdKe`Y$%4CHXtrSq*KPG{v@-sJ}w8qkIRL2<8~ zlWK)#S$oIk=z8S9!PL=im5h;g>_4{CW!a$#u?IV}1$U8mQhBtSorhJj66p95X*wxv zo_6oR!4A0qW9SXns)e~lqU=6|!4RRg{m0E6*r?4@u*%+8&Ey5~@E9y*GW9avT10d; zu=|&Vj}w{VOJ>#Yd$L;{zyX6b8vx=qy5RP|<_Q?BCawmu6?JMzJkSaj*DsC+Vpjc7 z0V|_77*~6GL@wF!`}*WRNo$KVNb!+~ibXlBe%+D0MLz#4#!@kY-thO$+yu;Rv}c2e z7-t!6m2mTsqZB-d?}Te}wZ!3F9cUq@i0Fw_ipHOgWX;KKcke$}n`PqW=Vc`f2)T<} zHL(z9BU6?Advw*Jmp8d%A%ydpVduU{fP-)AXL1n%iA=hjNbb21=!>}Qt%W$9;}^n$ z#j{(xA!epjm3*CSU&0a3fNk-6fiE7P|N?$VW@yZnDR+ zUdV(kT8t=3H9|xzk5{ZT=8QMW&Y_qeUbLx@JQ-ET7B7z1I}c7z`1-AKh%b@5z8m0v zI?zY&ooIimGLX50KYSqWaIfV2Vz7Y?m6W)WVa9QyPxN3a{Qmnt*-+*A zWtD0 zVkW8pT2%CC6d659Zk7L`DKIfHo8PL;{VV0Jn2S`2p%LZ!;x5#I@*hwGC2a+gJukG5 zgj%4A1z}wzKwU%JUl<)1W<7x#?SVZ9iqdD#P2ax!5y9(GG2a{tiC1qi^CK&~SRgIVspyvC0tctDM?Ghu@)4JJ?k{vn;Ym5g@1qKB9)4 z%Hbqhj!xz4meBo-?MkoN6AhSL$;$heiD#f*R7!dtV|Lw81k0kcDrGasAv$7~=HgCG z?EjkkU{$Lr?J6;h*pI1|o*>OHOw;u7z;=46n$J+ODHq$>%}~l8@8%CaXM!32y}SHu z+)M(R(zVaHx~rX8#VNWPgFSJEJ?FgAgPZdzo@DdulFu^b@O1{O@aZcUl%K53qwR*9 z_XXbNx0UsZf6F7~cw{jC1Ei~l&{t<%_ToX@V}TBYlMhJHf~>7M?WAT+`@d+=gD#TRuGvq@W59*eth1^dS$|AqT*A1#OaPyvyJq<6> z0uWD9I^p*_yei&;BWnLD{SfQ2lj@M*;mhr#cI9PvS$crW=kUMDYpZ&_89yHH^I8}f zk_rZ45(U@a2H8F$_76F~R5;z35TbwFjM(^l>c@n0+h9!cm2UO1^l$feYCkuuJZ1a1 zlq?p4$2K`xha^>puQ+`ft5ZA^iK}i87#_1oI2c!rJ0let@&?IjrFhH9B6nY99{w3g z_4T~88rZMnN42RzusMnsnVs_SCyAVsMI{p zYVdw59nm=tDIB=J$dbrHia)H{v8hqIYZE?4TVj0L9@bbf%=uRI?Tq1I`XnnS>Q^oQ zgUkUuLEl=$aBvf>qmH3U=IQ|bJ+hy^**}vNdo!%4T%gipI6mkMtrRW(iHd|mCJ+;+ zucH8=9!}Sw__t3{fqwFLyzJ$)axmA}8BC)0Er;oz`z*7ywdefHJ~Ujr{WyJ8C8M0( zHR<;H{!*M_8>Rv)mzrHSMxz!E6bBcVuQNQgdqPBFtW{O4n;`Yk;f_wb1h_WIe)bOs z9J;+ikbC)N`9j~Lt0Hl;wS6{$#!qv!kt37f;TzrlG=UK0*zUnEy!Z2`b(bG^!etcoWeM^9E_LR^#~g%+db4&ny= zD}U_sqq-Is3f->t^EZ8bAiXGf{_G*&?+Icn>Y=_?NNjITUCFRfeEx%t(iy7Z%jyT9mJ3VbEe%&!gV zd3Mc~5K_eNFmc#95Aa|@EUznc@AFcdd_Wk_wceVi9}_c_m2xmr);_!YRh*i=ah}xE z*YguLhNm@PuUc#7F6@{v(9OPKM`e^p_D{S_oxH;)xc_n`n9ql?id)yJJ=qH5kKe5o z%xO^xf6$)*z0#e|ODsP{6lcL{Z?f53JD>X&xT!t4_lbx?En{Gz$BrJ)FWfKq^x3-2eA)4oXUvbjV)DFYcm7Orc>eS?n%er z2=D$(m95^%af19UKLGJ?u$K_`1Ez&2!L|e#reH|3#W2eN*@m zFkb|lAsZ$5IEvOT&4a><{fkb3x$@H$h#ze{;tl*1%$xP>EB1nNj**pXA_*V_1rN|k z;(03$(D6$@83(`2mvP#adPW4Pd+S09rFW5(QO|KDwnW~zZO0dfA>^EHV^zsi zX)>bR&>|ksGAwi1ynaEjbpRnSGl|DI0rQvQN8GM2djZcdS+Jlmt0#AFBM_uLRk<1Y zI=F7mMY|j18Ha7w+8;OBi+!0RW}zFhktY#3A#A4X=!@@D>?PscI*d1uP93+g9N6r$ zjhaS154+hV{5SFM6a#gQdXfL?{5lGpBgQN; z&W2~^*>-|0pZQKic08fnT1JV@a3G14$!C3eLS1edgKA(WTQ~QQ`d&h^3|p&dDzh49 zhW1w}TL`dX(A>V;Y32kkS?E^uQhDz|Hhq-ZCUt~6*k?HBJ*0*ni(Dv!wrIxPx|L5; z`CFzPCi6chDB-e!(}?%Ys<)XQiMd!00Pt42q z94T|0KYKK9yitt8rckc6vnZzBt+a(jHZ%drOMo;-j4F3LSI#tmK<)02 zf1CW&JE~GByA?`r#OdR4GmPsAQp(F6z859b zPhK-*ISM8?Wy=RW>a`;7)!YhSswqzesPV3E!vplLU(NaFz>RJbRoCDk(#sYWec3n& zh(5jMoR~jRk!&4f0-O`!WZCIko|y(pbX zLKmc)P(vqlLPu1j7ePW(K%^HjhR}l8F2tU(9NkXO}7vX7GO6bDe!HleH4rhnX8RTd-~^&$8+gk;nJmvy@rlZ&na1tBE)COV0lAZAcchg zL+4~;g8-+#u>|-NF-G|76KCHFDT68h$ndr!K^!kq}fL%Vmnft{j?&FF1078|FdK^tG3Wd8uTW zs?zZ;#K^COC-JvDQwLxF_aK>@W5zG6%(@3=sS==vG%1Ky{=^qeV-pG2FR5`c;Aa{- zJmR19oU+CAHy84;69;Sw@`fyz%$_PA^4wykbChEu_&qoLk`QZP(xhM&%p&2ojO$Bg zn<*p4`|0rkT-CxS!jYYd$e2B?alN1 z)uB0`rDb37>5}-{5EC3roVu%y;ek4*QFe?wfdQkQk76~F1rz=rR8|)EA&0KGb?}G| zfdr@TWSH>e1L)wV#+c^tr|@Ty?xv(EN92g+?eNh{)i-^bb;A3(3LPgO)V!&L9Mq|v zg#O{Z9Dey+d|6v(vGtNg+5(Z$8}dV>nk}hiRJq4jL%XeiYPVRNVshU~ufjvOf+xrH3 z+qTuC%PtYmId;Iq&Nmu`JKdUKmZ#$Ee(H4`h!=XaH91=+SWmTt)tLLVE99 zXVl)W`%Uvpak;pnu*_L!!_(RyhnM$(c9gxGU~Ti#f0l{rSF%1>`6)H*n2<#+t!i4t zXoyT?N^MEgXSCP+(KaC(df2;0Sg~pvT-;}hr2X`(iZcTQKzRID9{!6D&cpDo*gdg}%6Dgh&9Cul>`y37wtW zmeJ>~190T`23i3$oD`#Hwel~w6yJ`n#24Ow!5o*6UdEjzxrE0#*rI{v{r?$^hB+oRrsI0TUaQJDS#^gC196C??XW%IL`5xg7h#a_Vo z+%c=)k|tdVb=lT^uDqY|fXqv~j-SdcP*=5Cql%UV8NrEBQw4*x2SQScjIaYuUs#D`?TG@X=>#y*Z1{`Wdpq-9JCb4R5BpGzQYxPjb4D4o^UfWS@Fc*IRYUMrg!1RV)QPIW7Tc9_yC6M}KWp`yTVH*dJKx1yuBJU1e~vEAybrQ(YiPdS zOK`i=`h$F;!)0D^Qgo)UK=6Su?Q;ZKKv!LD$R1T*B)^ z**I5R38(f)&p?@ohg&!&Y^iC40G>dKj(OLTv*&-oF+BT&*st3Jy3o%n(K4Ciga33S zG(I^ZVgKwO`FMPp-3!^0GE|J#sT4w1_yXKw3UB_8!uVag(#tQINc`~tud3q31VuE^ zb>YI@EAc3JLRQ8>{a?OJEA)V7#4@+w>&8wE=2)qXSGH1coJL7xihqSqwO5$Ene+4o zVH|a`&DrH4?XjU8nR8Mjc02J&qGJt-OuVl3DL_GzG_!A^a5of@8agN>ybAW`&4pTazK$w zzszN_G9$;W#{`Up^J{~Lehqzym5<~%xi;I05u@M?CrRsb&1)f7dI?3)iOOr7JTO;} zFriw>=Zxa5_<%YEQg*8j7dJ6dn8l|~9B6TB6d} zkaWEVxQ7qWGqPg@UINur8-FC5f6HaM3*NC0t;aTP$b-B?9^MokD_wLqg4vDiV2yvi z{B@4}rjL4K@NKIT7gN1F5)6VIRF>G~-e-~zj@^U!0P`K^REv1COT6>ji{-gi*18=i z!QU8}1A*|_qP9nT^y@?t2z<-(UEQ0~Td+J7_2<6{iaHpH1ey$@Hw?b3XTS7*gRJKIE%Gk^KcLWfZIjADp9h5r7QO9%1ecZtrzpWSoj#<5I1+1z z$_+~-Eue+0ncYR4gr07iyibF~uv_VNXzxv#Qjl4zR}-e_D1b#&aM}=o(y*;#b=Wft z^VLn_RIEYu+&XX5pNoCy^jP>a@Khxg!G_aa_8kz4dG}2B#*a?d8}BS0w1eW6+LK?# z8Zy{J8;zCMRtd-x8xLLALHMTiRKp#GXINbfUAo!#yxn+(93xQid+yl|XdM2C`s|5;O`I1)nOMLwX zNWXixaX=?{pwGK&oY}#5X=&16Rxlf}+*wt=BcT%QRF!9rDCq(b)YHb3FL;5|K$b52 z>vW$GN$?Wq=DcBg9oRqHQO+nHri|-PGsRkA@~MK)g(45is$pD$3QNU`v)V&V$z@45 zdh+Ah+TdF&#wLBl5TdzmwdfbeJh7LgeNh+uItwtOsS)0~(VHJPhUKq)qMwO*{H(0% z!t?!f;=U1I14_h3+vnxQHA%R-BUf=j?IjdM_;e=e9V}fMgxYn=Y61j}Yb3^+1G!n| zcZRr`dWFmGR5QC9$W?~*1P4c&416&_()IjxiN#H~`{I|u74P55t9)|ky3m6+(kO|zUgRyv!usq#iq?kmsjRM5&%?a@dg1e(=n+7+zBhpfq* znowt8)L6$ChC`2)$9wT$LRCq^F6Iei+_|}qVt{&z-iaMv#E*%S0mklQG0gu`X}&=@ zjItg_%mwA_p*Ig}WNh~c_d<6D73F>ZfOY$gn2kiUe0ur}yVqq&#c1*?=@VrJLv*0S z+cqQ-O@#__>HByRC713UasU0U*dntI0Ba1druRjq$%)dlS? z7FsEEz_tm8957PmaP)`@>-R9(CK+CyM}vXEAntV3?buT06)tN~?>F0o9ci5a^^m5Q z-V$kD7uW9H^H27v2nj*l4n*LgV|18kA0OFH_J6xfyV5qc+$oiYUdzH(~%jx z2NIhGahRRKobIJ!DdyOp43KRzO%^4-r4S54%d1tw=mV?H5~1~5Z-U0d4SwT__uvgh zA7V}zEC!f=l4ts4=Du-=__=QxD6Ucq*>E#NPQ=$9MB0-cFT}EVq4R?Irt6~Q)p%ZE z+*p_LWlgZQiE2hMn@}`m!-AaDK^tq!R#usP@i_KRrE0x9E1p-Rdjc%Y%;Tn2Kqe2( z%$4`bF~zm!3c40cUx?N3T?a-RQg3cEGb~LgC(X;wB*qOo_YKmRS69G>GuV0Ei3%t9 zDajS~@Ph+o;ul^=q9Q{NkF?qgm@CI(wOyIBx-#-sv*Fey3e~x^ujsLGRjYfP7?fF2 z4Pv)9uCE)fXn4Q+Vpg+mVNRQ;RlNlWaVCAgN`VDm4Jj$BfjmdirbQ+wB}vf!seR~S zFz<%b=t3`RhFA^%(0H1P_-B`bue@!S+9x0+%6cmnOu1>$IyV(3TNz9b5*n<_n6LML z(mSnlPjU=)W`N-tozJd?;$}Y|%&NNl} z@$EYj6lU#;e*K%4lv@<7aSV{?7!W!0o6+y!m1Vx8sRP$;VDYC|`_1Su)0pNz;>Cgo zPi3kdtU&gHte|>S5mP@;{BtW{cOc{#I+2|iol@7Qewiyj%Dz6etq9tJE*m4TioAl6 z{42$K0dJLuspDLB=kvh~7i1)%rO4AW-`|&mm0Et=AQzMlDPUSwqjeYTf;l2KS3PwQ zp4O4|C6ng{!4L#ROswfydF_?kUXL{%)UemDP@RB`qN!_ss!;@5;BceMVpb~=mn}~V zV$k3kq;!25T5WC;CVbS%3%)NDhd8Hc@7obGmEqXYf$posDj%c2#daT7{^JJ3we`!w zZRK7TY8wIn0r~Z^UI6)S*P<;h#6~kVhFu<9iZ=@Oop?Vu2!$lf*Iq z8`x~K0z|-4tIJOymFA+1C=X(3eXb=hG(dQGwyom=4f9Ie;J|ls)D-P%zfoDEKVrzv zlXrf0QfD~j_LslE>_!$+SS*Nsk`@rwj_RlJRPd+YjW;n~kM7a%W)T4&0N0gLl)Ww# zPMbb#J+dOfrc_#p4p>>}&Qyaqjq0>z7=dCj)Gif0hEW&NKarml-gmMdU&L7#*s|A; zZOymK>P0gZ)9^om`Et@;&i$Q0x41=BNDdzyA_Uc}vsZaC3%;!Nnt!1^h+7hHTQlLZ z%xuy!o7VMt5b`iWDW1cm$bZ7gmeibpKjf=li@z#gBBlK!!#PTi$9VYX*Z8noT*kuO z`&WA2-!NwV8dOmya+^xw+0_#GS@rbWV;i1KC6lFymVw|=qYdcuGfS0g$&D;yDOWtC z>EWMa<+ZR5C-x0~Z4L^#1ZwK3%}2Qg4O8)2(eTz+wr5K#GD%Ff#Z)GSF_&NC%ZVe= z22q}OYd(MQy~i|iS9&)TM>IOn?Ac;@@a?;~qNYgiy^{xWHzma`Gop}47}pjU^e>H{ zc6h1VrZ*qZd|qS`xc*$cYM}D7uP5KO=^C@JU)cg1EKL!&m?tfwj<`o#n2rcmOEW7z zoY;6n`{{6&`RFK~S2eTQg){E&(p5gxVZWwvtx0ctNO=UhJ0vZ5OgzHfW-HSC{7HB~ z+XW}tRUrt0H!>axU*MD`A}c58Bo>;R6;M}vR|mKJp1VnXcEcrLdfUX!nu!*yQvCNW z#P*k6PPUM$B)KLSNncVjjwrU07o3Qg@K%3fG;(v|;PIK?j`QYBvx^Cin2;n~Squd0 z**S3y|I0q@KmT>QssH3``FQ%w8$ER(P(fee_cQaML%&^0&F!9Z_b#uG9+y1HMaLhC z{jAlwd))j8#$;9;!Oz9oB;b;MB~Xb^1)JSJPG7eQbYlf;C&_0O>u^ifB|Lq;4EMgA zzK-ci|0Oc|)c%h0_6T-2;7&kgN6|}!e^$E9EF1PdkG=kvoMy}*O4*^j`W=f?Ymd^c z>tdVhJ1d-}?q#^I^R!W);FSBqW)A;)%Q{E|N8cXroxvXeLcz5@YPa;Xz;G^yn z<@h&Cj8OPQMu|rv*C?twK!3ITLPCZei#dF+#_xMQzH;w_{7OHRm%cs##I+?|kJ#;o zClr!Ybr8ZuEM~dnzB)EukX!r?tJ2A&?XOQrWikel@oBEA@7d*hFOF3v|6cETneqt1 z#Tl>zesA$!tZ7PeFZzV-8PB!&2i)hdj!XB_2CMZWkUiPy-=LFI>80x#yH@XcUQ01c zHc|PLY;|HwgFukdI=szv!BBt?{!9ct8LDnW_oTzhQ0Qx3763e`wnR(Iyk*+B)Z5md z;WZrjJXJ=70^+*PZAW$&pPw#~&13lMdcXRP@1Qg}-G(qVU*4e3Gj`MWkxYMZC8ZzW z-X0hFMjP>D&RIDbAHn&!n}*!Prh*NjZC9UOS=A>vdY4g6EP?ZH_ww@*;j+ypc3Kjt zc&&(p2gfZIgZse%7BXBC70#roKG{*Piu~}x0=jL(+rx{9^;1%-nFH$HK9$w%LooEM zvwc8zCstg(Mpw^$VG80AP$DmQ2nsQCt2`YZ+d+yv`)hM=39ycB`ObHc^7I}5>9N!L z#zL`vs^Qv^H`%O!9@Am1CZrl*rueiZ7=3!R|@0gnBSzmPK;RY4zJ3-FXz}DM8$!D_L0MGWZo%g_A;y z8yqG=P9W{BJE5SoA}1_DuC}+P-!RI~7REIi%;Kb=OyTQ+yF!FI$X69Bg7&9J9Re8- zHZk(-jTk;i8;mpINhNq3Y`p*lGTajuu-EslwfETEid@hhG(7pbv zhStK7*|oT!dJxhL5f-Rv(43@Q?QEiJ1^gMAm>$_52bG1FX)+n%e1diYzFsmU@Ajy| z!f)$g|0?leW6ph5i} z-zcKM3WH(5waFHc}>i%O$@*{xia z*~e&7Ud?jqaTLFvI@)UZ-GqYvtoHXaKdw)uQP5;t#ny8|vf-MYD^uTP;fk*O{Q)I?A;=bCS+Fgyt4!Zeq zk5BeN`b#p4wGUq>U6`YBmzX5YDY8hb&q~5nW>}D-$I+4<+RGlon)FuNy}eO?XDIt zZ;o#%b+xoY)tQ!?2K5YrjW@TQ?N1Qw>`rnKxAW<#G`^z&ZFVkIB}8q{fc z%v~xW0ipe5(*Ds<$8icUtzwSCzI5PO-xUJ!pe;{dMp#MZJVFWiOWINYMMG4y88M)YmNVj$yg#`KC)x7c0jnxQM{}lJHTONg^J!r@PhMe)u zrHGhNzz2`Ac~dDpGhX9qBV`2wdDD=i^#;=6xmE3t!^H+d2YDrYH;*R<%PprX_2Noi z#`G6fd&Nyp-fr@jvkF9^P-MbEr$mF-7qlz!G90xdFFj2Xh+EIXvpEN2W19Z)yVdDombf(XiTWgKf21@ z)v%KyEB&A+-7H4}`cw4foTT4UQJYagdLldfwQV_z2+;-R|A3bJ>#0Ap%s@Y;8s{gO zDo*$h)FfB+*1Stf5?^9AVp8Fqc|5px+R_)S{)LLFJDSliSOA?g}xHHIo)t~*S#b0KcEZvrIUmykszH$ z;h02c)8P@i!(rclNyax$(YYGbopc0D~+S8 zi7&AORZ-go?oct1-B>#s!A1^02`_N3be3&Mst^D9>}P4eB}EhS2T}OKKsdhZ5A1bQ z+f=~KxuZqY(%sjYlCXcj$NwGj^n5uL{kT@NIJdX9s2B|Ic74-bj5{3s^GvV&G2KqY z#Hq-HZtUEXZ?F|2H{`GD_(Qf$+Vy{i|Ek?ezTJFmaPdORn9(~~M9i?^zu&ihR%U$@ zE}Z>Lxlz;4YG--Cvk?mXN-ZOwmd=aTG{N{H@; z3FSvCA@(GEmkN=6$hIY|!{6{s1>|o+rI+mZ+ia0Fbs{Rki_riQvw!vA=fw zTQmkUq#!lMTN1yW$=dJ6I14Zat*+=5^K+O(hqZ2+#rNONa7zw`gQ3)ARfz@ltpQ@sjr!l zt2n-7K-GV-rgFj^+q8sxp#96Hoj!Ak^%WT(quQ9K|JOH0^POrv=iC?LE2-a#y5eZ# z4#&RTd}bhL*J*OsO~&6RK(^w=izn{MDom*ru}~fCM+0lH0k;)&s4OmEIBI3;>Bmt9 z6;{R##tNt=%SF9cVsutquZp{|j|jnaB@G7g$O~f~BPfo_47*1_I|3eOGEny>zP0hb zHz<p<(-Mt2$5($gvgwBLiNo z67qi+2y=0Ycxgi|(yKAgRf+Is+8_?-10^{oN7psmxj}WIqE#j*;qHnCmXXxy#!+ zFzxlpW!sx+Z(a!7y><^89Y>$idC|j&zB}LEu`eVs8C6M>0?oYL4N(6*f#T?q?dTf^w;669q9j;>ZidUuLtCIXoO?7*0(&yKHPCS(v z#k#-=0y;q^K;g*{h(?z69ofrF>gRTf74#65ijPjbmGiGI>W9)6fT?A*qrt(~#ar#T z%b1b%$7s&yLg4SIZxRZdJ64|Xa=Lg=PLQuZU?2JmEjFUB{avg!lWjs*k6HnUx18Y& zh!ciU(VGRDBX+s^+3`BicIoMN@rjTDo+1)^w3LC2OGx06T(_vfG!WO}S*witQ zHzMSR?KC4CCt6SSDGj`Wrs^$L*>4R!j%E<=%*E=2v>uHps=NI~up}-K4Gj$BX|Nz9 zln>q@&&g^8pp0Z>nHSoorj6n8(H}2+LZG-a-xp9Ed=Gy>pE+*kj;}$0?jMa^rrAtHC#d zF-y~~z2VR;CHrT%Z0g&C+EQzw6j|yc$57Bio{Dl8p6T89>=4ds!V0^#i~UV$fBCNg zDZa2r-0|wJ1fTHdS<}Mt#-L0zO^wSU!J6JO^3i&P;e`xppmY-p-;O4$l9ThgUbtxI zqgYPi%6*wAgXozAC{ktQi$~)Vq<+yil^Yp<0M0hCnxM*wH>=ei_hu@e-XE(?U$yZFikh*194^sjCvl~Mui<8Q zapffJ?k^hO5n`v-K>}i#n?SvNNL7aF6-?!8erSoFrmC=K4Vy_W^H$%~A48-CD+Wuq zIuR7nFvw!di`RZnt;cDUJ#Ym7#&*;T{7IZkEA~PXT?Fi)vHXMh7kU&;TO?eVOu}WN zs*H^^Tx}Bxhl0KAK_Pu6QVpy&_P1qcJ!wJ4r#i4tn572IFwJl}&*AXp(JVM@2~htm zr<;9JdT9KV7ryR3HudS=&n~CCDj-H_H-AWB5JNCXqsTy}VdwZ6r-6 zZtN73Trt9JW1QQ!@O4qUNbcxRc}{9puI~zFP?t4v+j^)|b5a-XJQ<;S3#;tJ2>(*2TFAB~1{Sbfw@yUteB z_2GiDaVf)o6p*5L*9ycWtQKOsQP!u~W8UzXK2$=CRr860hkzck zUHe&W_zIzt?N{YLw;kzgQ68bS%GecyC=9219oJNPWT-h!LYL!i+C=qpZ_78GE?n1 z%}rC8F}1Ax%+pJS`^!hHgEu?~&=r|e0!{M3hVlUUl-@75_k*EY{akz|W3pm3T*Z;b z7(!8rK+n+}KxiYeSrhNmUUjxHzqwxOtDkL;V*pOkI)V1&wesb?R%SZ1*3Suq{1>^<-nmz>dB7& zZHTv^E!>f`LWk63Bh!3p`sg7-4k?`AP-nkSRjzi(^ARARS2AX5T^5vowPO$o2AOo> z7{6^X(qnv4HBV8CBD)SCiRj5fB*e4&R$d|!TBKb+W>mp0Y-*(Mt6tq$%&Jb$hD`B`u1;F8+&6+^ez8-C+tqbsFH<}eFxcm@e`L74xX7P9Qo8iN&4_EZvrxG$wygFKFBpsDvtiC8UOSD&)yu(NA4-51tM)h!Fp*;Fw)yxUqDzXxt)>(S%VG&>}G(@m4jYO3|_Ct}}*)wVH zB40fgNX&4=$42nfh_XV;2H>!h8GE3vY|xY>HMj4U#zO;-&vSS#<{4(cXi-_l8*rA# zqlF&6p83+yik<6UVa^zv3i2=d7c9dNvs$ICU?;b?YR_yM;f<#;1mqU+IeR1PAN=K# zPmhlLW!Mz%Ys7}6kwbHvkv64mMNa zb@o1wZYWi;BkD1{e9Jsu0*(W)1gG}Gc=n5KJl#E->3{7C4x{|9#4oyM5K}{ri{r^v zi%DO^!u_0`^x`|RV z#s#C}pJBxqi5W^|&b+8%z-Ru(U1g6zT8l|_G@8}VM!IGYp64(ed}F| zlYWA~J2Vprgs^kOe%WV42rEosbI4mN_cz+rstg7N43#E-RvLXqWQ5=0I21X%yXrXZ zH^%TE5ax1TyVg%YK{7g}Qqbrj%I=0g5y?L@-UOtKiN~)W7a2<)7bzD$A!l(Z4>5>@ z3YHAm>uo9BEVwDYLYXc736M(SxGgo}Y(0uGnxI3KXAJEVN1Xxtp%NM*ckCxIzEl02 zcW=gKn8BRHuk=2L;s&WRjn0?|e}T&UFfXxSHUJ5`f!zFI*VvZtom$&#OQWc>^ruhM ze|S}|JasA_BbceiD(QPfCpMkCl)1V*Jj6J5J8k=vr&_D57E#JWn9jwpb)c;OW*kFY z;P;byEAB{sjGH9JXvO42UVHZiEA#IOhKG+2t7uEqSxq)-RN7pm=y`cdr+YSSD*vDP zIo1ZC|2;?N|HsD%wbk_1H{7LfOU zGWK24UA^4L1827NZcy$Wx1J%@V5%eZL(=4uvjm)hoNoKqfu=nSrrQ!?ghQGUfh{rUaiJvb*hJ63gt-Vq+r$3Oxi?4V%6>37?dS|4q;MN2M!ipR&f@5(r`2(Oq-gWM&EGX1Jhw}G(GKfD25~t^8 zYW)-B!ctzJ-vi^Y?oL5L@ZanA9dQeQ**Soxj7uN9p)jHdC=j_H+TEVw*zQv_qwn7H z6<5umE2o*DQHs}Y@ab1&1|fN{!yH%6dt;nCmgq*=WX}A&4xew<$z=bbyw1-BErAby zm}eT!p;tJ@e`nZMB8Ga4gCodJj)GhnKb$3ZhC62{d9qxQg3J%75KZY|MPutR-DpaC zl$m~`Jm!QTeSz{BqmKmAV5+JeWG zovRq&f?3;(kK}F`Ku5yH2O~nd`D(5sG9#xc-#JXWNz5zJ(k-q{RI`~3-yKiH54S!% zjZ@t19Gd|u?NP(Wdn|8ek8)j6ng$;I4R-@Ner05tVII75N_ohjLh4#y2@n7@p`Gd} zZX2v@SJQoXQjCS6HPwqH*2$A*SN0@h?gu~a@X4~Gy1AA$ASl`4H&iFEoaW2 zrU5untIg4*wk!%L-5D>K0}gXMzs0is+=?5G4r1kdOWjShp;4RH_0r5xn@Nx5Y3JWd!DW5>gT6s@-1Gg@2Xc)oWzxoJJXl!|}iABcr)VO@zY60(Gu`bhE$<#*s z4=Ziooc@_Mp!enykEGwP>PZp2g%B^mSWqM@47S>wrV za9o^~aGP(pX#Qdxw7fw4TP&Je_O0=v~+DkJk$k%Qokl6T)$Tt^l;>CA5^JL z7p2VP|5}GibRmX(YTs4d9-w?N9#yigy@V7Bu`hUf15D>g)lM>cUJ;;qV)x|r?@jDy zYkkLoDppp2LPRt${Ka{H$H$zdkC?Mmn2yh|XP8B;YZ{>GJ>l(ARc1Mpo>eL$;a`O%~Nblb+T!GT#7DM8~q2uI?j+=uExR;NhMrLbdf2JkD9V1Gd~| zSA-VLzFCnSD*3#pnmUEuS+G#&x6|ci4spKW*e71#X=q>a+?C55jb53~HtT2H@K@al z%ozvqrU;{o9lTEu}mS` zi zr#;iKAiw`FNV@^sa_4n#$k5@b-}IoUs?aa}yw~gxH`AzBEGf#_!fgl>el+9v7oP=Z zUdcHknYP$;vaA+zE)at;-D7^4i;5DitYBK^v}Zvvkq+?HWkL?4oPVL}@tuL`p`#H^ z@34R&<0Ja=^2Wh}s*hz?f85CocOe?XwGQp+*n&&r@GEh5iN4$dfw9jjkrs0^-JGuKyL)*OH9BK|#ZrsR%2}{-G5tAahumCw@+#TVF9DOPG_X7CiaQ46 z`*$onT0%01=^0K!N`^{&GG$+8BL@-bzYppgd|Cr4GTnbu5OFL~Pe5qiHIc!XsAis_enJDr7FEM%Yt@E9N-vZkX(Z=n0eCd9F zz9y$~bvsA!ec;2K9OJc#JWGzxV*UbjWl`1w0O%ic;6E+OHw~2D4F402f&ae8vD2GF z3?GpD^nS8pCGEzA>v>R(C~RD2#ICLfV0Xf^Q#YLi%DM&l9sX5AV|}?-+_|3>RkHo= zlPk4z|2KU&VlJhHIieoakRBd{ZDT)_$et-`=hsFv>L0E1F1J~{m(R3(Sdydz-XsLE zSON|NLUat-TXqEA1cYrjYOx(}HZ&#By1NM`qVDYiQ# z!jzUy&%yRzY{)(koc9+iu<)cCv}7Cp_qR5GE*dvDs#DXD?4fyFdtFg@Blq^dZ)112 z{DSF&v|m{dXg^R?pj!4$jl`mBzMo!x!J9v4lqcW6RJ%VGo-QmUA6?+7AYc17yDVL0?fx~5uz)LZ9v_{{)m>ShtA>M^k9hdwBYvc1>WwOm z+naCQ$xZ0dz|F=;*P&J-J*HEC_6jby=>^g6h}h`gW4vRV3VEf~`kFCiqKJX-ZUe1X zuo`oW^URw46)9c>;m}PXKX$}HXTPveQ9q)-(k~@07sSl$R%da6#&`wi;E)4-6GPSs z<`#_W;Uiz7V4e9`JMKKp{+qYPy=j|*Ahc$@7zOck9iXsN?FlQ$l`L~t=DIAbVQ@8E zu<&ti_Hvuolf~X)!(l>l#e=AG<$a8ch}onVf(Ruum<5!ad~O2Zq2{5zGLal-(lRi! ztd)Jh9&P%@jSq>`9(wvW?g9OER^OlT9^Ha*n>u`J^^UGCBqIIfr!5)719?-dDhylA0q1x7IgE%Y!YvUq_bZSP}6~g7_)nwA#=TAh=eW&?cfrs{rz|KCiE=^$lHcrTd>pha#gT z!Jy782n6>%Q-je#tGp;YB<%7b>^!I1MkcCa*Z6lVFTm^6ti7j8+e=^~3I4P5muH!P zOqQ(p?Q}42skv8wbNcXICFPyxvP3Z*Mpa`tfrwuJ$-Q8+22x!9S8;4#WY$n|WwSCc zY-|z4@ppQ-mZgGM5S%vFj3k|D*VKJhKZf)Da2)ZwYxzyr0Zt}OEP9gHA zl0GnynTU%2$Zir7S^f3IX65#31_2{7Q3mW}s6A=l)cr9SiI8JIn>|<>#Lz7PFD!xe zNBjqbtUc<(K;mNk9!T08p675bOsI3Xu;a!W3`m&TX*4BJP!npg1P5P}5%H)XA=(i@&0AqwiAe;4KMVrWLwlb8~}vA{rjwwO%^$Nk6{(zK{f$1N%#+s?Z7yd@S+8#YkJ zCU}B%iK(M@R6-yLqtYkri{yL@AgE-;1Gj0V|M2!=HH5(Cm)s_+2}*YTX8C|^sDgAY z>$f0LIw;7JcfDk&ywg=wvsnQX$oV+~IgI1@?^Y(sCQ@YHLl8W&E*Yvw1zK>0tp;rp zhJuhyYg4u3{K0{xv~1Rtxks{}g6;(Sg}x!b>UtzQ_<-3pY`IG@_yRCuY$`*ShSg4H zy-HY^aBk|lSmAbl=@<|t6-j5@|1|Gj@S5Iyks{wJfi42Z_6xL+$MSV%R`#{ zARP#Accsn#(v+q-ho86rYDcFg5Ot%o2YNu^0=ZAw`6s)6MzA9(X;TzUrWRHs3FNv8 zKS^FIyAdNHp*($@&m33yMV2*u?*mTDiuC6^J2jZPSaG3=4Yu+tE!3N+#{cx<(~pX7 z^o*P7&i;a=e>MY4{O&YLSqb;VMWhB&(!*`swor&GjJ!9j%V~)n9PO2h3x_*_*ta z3_GARsnTD1u>z2Bk%`tV&+*);@7D8aAG;;O4H-wg=T?S6+X>E>EkGK-oGe2kqc}z( zR6J2>RGMVWSLq_my?ju&UlD;wlGyH-PK0wduV+?zrFPM&P=wxI!eo3Ut1ZO=f^75D z-A-LgL&0+ul?@O<2es=EbARM&Xv3?yu7BT}pxtVL3`oU<9M&6=8PbQv>hM7ei!3Z5JaS_F4iYRqe>80GEC*VkxT%3CSlnEButE;) zTBd=CF7c*b>+&1(%b18!4xWfFv+W-{&DL*BfynBH(hBo z1SsVo0T5Sl@f4YR2w&i5Pv$6`5+Tub<&VH zgFvhxA4pFfsjv17tBUmzg6lJl5v4UNG?CMMA+79; z&^J;8Xe+0P%|R7e*&%$PXLonjp~yrsE|wAGF@*wSpl>3l6cuy9aVQPI;JoFany{J^ z!8f9xwi{mwvW)ZvA;FBor;~HoM32y2`<$GNr}yr;=NsesW`#cs)qZ%H!_2TbV#}q( zl{BFF#1H{VzWK1ydT4ekbM_T6()IVJpX5>Yc($8uH?PsIFoS$|x|xd&*?3epoOAPd z)|eO&f?11oEE6UsM22%jcN3PA**rJzt-x?x)ugB-tUq=zv%swyA6H{bcL%1`>8I)|;8& zISrLcCMXNYkk(*KpOk0VHw?Un{wbqtZ+_FfCfl~TjGvVH#x;-9SfL=K-~sg;Mj%_= zcn~_1vqq1W2SG_Vb7`HWi_k9TPr+Bc%Y1nSLHGNd;Hx0gFY2nTyR<@1&#nWB?F#en zSX|+d$?(io9hW4AkiXN63-qHpqmj0I-=33$F}x_ikSHGht5}i6mP3h18%&M^E`ipH zP>Tyo@d_5cOtHaWI9cjJnRXQ6dwsg@Z5YbRP%SNop&zMXAIa|GX@Qbxa8C80cUk7` z_d`6!7X;jLMQvzqT}aU_3rU#Cm;zm(K?}zFz3yX*k6rnfWuh>%40vk|E8sx-vj!*A|gjfK*{R?L|leZ~8$8m!V^ zUUK3H=ylSx|AB zAGAEnW-&w<0|Tmxi^YipqmkhB{;D@Nt9u9ETkd|nmi8do2U(32)n&8pgYm&4CkAwg zL=5drks0HTj*?)w&1s)6Ct3s2XFa*>4%cEGSNJ&r1^ij?BI>96y(@U zD^D4E1(>n%9Dm)Om0`OfQ_F>vDBedOQ{2anPbJe`3qKPr;!*q6a2OEb_FdJK9ar+M zD2#zYP)-pnAv|@Ai88or2Rg&qMW?QQ;hWxzVG@anf43|U=pk}5<>XUxECxh_*`fEJ zJLgnqW4UpCKml=2tZ6|;dRaSFrB=~j@9qES#@d@+aE)VBVZ_J;BZ0__-jou%-Q~D6 zyFG$L39%R%fSwAEnoAD>V49j5CnmuaMTs9K}$tpCnPV?9@%UW{9r~5gO zwCEYAkqO*xImF}Q-ef%j%e9CF#zCq{AYdSey%OW%7!aJ~`@n82XoEA9Z05QX1h}?% zM|~LwC1$d?-SYh;-B=Bf1I8bi01k-ou(>XHA)PuL*@)9z;pE|c6U z`gqGq&CAXIqG;E$hmHFT(i9AcdxKavQrzISNuWy{72ahq!goaWP=78Vo2mA{arfr& zP`3Zy@Hu8ONVcd^gTZ92F3YGH42Ccx`&y`kvJ{z7h|0{^r)ik66is6tV{EA?TB&R; zh#^TOYnE0dik|bjuJ7|(?&rRr`~K&9{c-;>FJ9;CSU<;k9?R!=f8KA95>6q@z|Pjb zFx>c~bI0ZD9)>6}(^%oU*8oAeqt%DsvcP}Ba1YJyR;P7qq;fe1SmlbZMB7c)lYtjI zVVP|_&RnyU;k&mbtq4JI%kC!J6(S(~TyTamhwxy3_98n2KYPixy7;FG&-MlI-c+h# z=uy}<05hx>Z>>X8$L;zA<50q0$Xyp|1FH2;;Jy)|4sR#x_W|HKCnXN@IKJjuQxXCN zOa-I($-0Cqq&KJl7j5Bl>ye@m#p&n40hF!&`N|A+(R4suCQE;(QCh%NaBKr0a3B^+yzybJ|3) z-Do45zRu^7OqyaX3CKN){h)7gAo9S%HSc|Qn`mk$v+Qp**egbCr}+qH&cbVaqf?&R z(>{eimfNG@UW%rYx|~8MjtC3rC#>T}iDMG?fEoKk@oAK<>at)lg5spAZ=OsP1Z&>! z2hC%XTCgSsKBE3R7Vf$=TTlm_JqA9!+z^2H z4OlGrI|Sav{;U=U6lTPefhY$bv`#V#6%9QgQ(S4rNx=702f za7S4I6MAz++9=QQ=src-xhT^GLDYou^(=w2nb(CzIOCW!WP$%o2EA41mHQY*&In!` zHjE=O65JIh1#Na=hTYC0eD)potwt1 z-V3?<>cfrGyzm2DE^Ti?b19|RQNDGnUaX^hJBF4pT4>O8N>d(moqdagBR$i(GQ(cw z;F0&_f{-F=5aT@JdTiOQntK*5C4uN(tSECeWG?ZaeX_6(6y#VTJz^4KtCGb`Jq#qF zNKSapr6&19A@hRtMz~72HCI(OKHp0d9Q@hVA0S|9BtSJu@msVyqUEDgloa!Od2-tzWO8r2HK=G~bmp=oEC|Gqc+Pcc zU0StdS5+rH9R|=42S3)y zC2Au0%o8Eep}|RYQKr{MygfOaDa)PR)4r1W{zGyIF`qEiAC+#e8w0BijF~F~QKW;D zHzI}}XWc={-W9xTaBeM4&H=b&lC-rsgm*SPQ2fO-se#;T77oI#uWct;EK;5v$|+WE z*PJGPfAY=%wsD#i0j+t$tLk#OsrTARUQtx*a!P04HBKzqD+0M=h#plPQ`iog!R0pl zU|=cYApGS$uePlq#WX|X-fP&zXaASEId&};UlH)P70?ds$YK@CJ2Z<%wZcIkBo15| zuLP`MwCwiyuD zUqOy&!1rWu+Nmcj>XJ#(KpjsyNOjo5?RJmIXau6 zw3~=m&Oo1ojeWUl_@$xzvKr&~x>wi`4RoMEFp%3Za~k@!HDQ~-X2kwn(xE-z75@H9 z|Jdnqh7+f$5(lr@Q&K%5L+(*+*l#M*3LSV%jlxg=Simr_iX%o=Wv@t*T-7j_H$|C| zBAt;CzWRmWbuA`;05bJ&NieDvUiUFFfJL?mB1Uyc+nTV5-!Ug3&ZNmwqtr-=l4r3t zWmA!7^(*Ya`#8+7^<+>vQ3`%BB=Akd;gJ`?W6VrBY;}(SW!)5JQP|aJ)M2EbCYj?CZ8x6$f0^dyD^_DYEEj1Suct65#?6_SqI}@5R6jv%Hj*&76r%P zaEc&w^libQ3&lzXewa}|g*vNOWPa+oFFMPD&aZKBv9cC_H~+TeqVkwX#E{vX=`!U; zG;%q(aBAzIKa?5oxxWRu&}tsM^Q@3%U=+XNVXc^DJbYB(Zz@Da>D?zx-PC)0#4+e4 z(>)-~0OY}I=WkCwZWYfaXaa2B2K7$VDL{(z{q~v^poA)8P(kq_5(sIV&hA0<01Tx4(}g@D4lYzbRsY#}zjUSl`|&-Ba*{~Mv`?9X5HRQ zXZe4M+C?h73y05`i3To1c1$MYCCrn4c%{k*(12%#V?1f=N6NYPa1-({m29-|=U~$KN8QaQV00q@uI7LA@(mFQTP4@IRUH8A zqFe;M1+TtkOl5|jS?93?Hxnm!MZ4EKXrj4Ci$8?szBu?6WX57WQ@#k_cEph7a%(q*a1r|8XIhK`{YI1hlJrX0C%fBrvcrrOCo~Py7 zEa##*J$JV9(9K+(uNA{(h8-P(SWbKB=i2NE8@zM39*J)9PsVIsGj1@yR^*9pkhGtNfiC8^Jyi83vXVOX>o37 z?yGCPPQrF#K9;rpz)lJV<$V&w?A=)PulD_NILt3sUUY7NaQGw z!DKGC|L9LxJ-F5D@sT50Osb645;{?@ZA%FiJ{S@A8wl|9+5Ir?VNJcET=b=vu%F(k zu?l#*QM|+Y(bjT?Et?VrahHJh1pD;G^zr+vcgu5va-l+tWHC#dLp$bBk&%#TUitmB zFWbJo`=Rf6O54yH6%bD^{No$2hUpBk1tUQIi~{*5e(zK zq`*lkG46qzbIaMi+6c@ArYv78&e9k8#Ugi`gv8YJ-bMf}#QvJ5{s#1{qmw=uJ3nkf zS?;vR={a3Kl|*#G?2BNyXnrZrZdErQdz-}zE880=oU&M$`)YA3B z%@R%f>@3@}YI((go84W5ZqTjk7>Ykxp%o=zE=r74VLV(F4#`*(p5f*S0n4t#X`v{MJ_DA#|T@?!Vw{({_35V(ogvf2f|E2;SK z%Sgt6nX(Hdt`n4K37Gc|>=*$TFuMRaG|4*%EzjoZ1^dTXJD!^sE7sP*M}_ad4S89R zJQj*8mOLML?(_}tT5#{FW9Xi$$HTNIAst|k}idtT$yNe&in7qK$DG9k` zXD4&IX_!yLE|*KJwEh=TWWofL|woQ zQwcCunk66G*6n^|2mVb5I(H(Xi-b=*>{tpz$|u=|Uknm|9UGi}(A=R3fww;q?uUwgeDwyuPt+(=iTt?b?I3 z@+{klBRjl^nwB{8b6TYhy5{d44J!aHH9@xKV51jf$XbI5YE#pVy9aLMRQF<%ch-8- z-zzHZyE)DxXfGGs?AkQk2-_ti8{~Q2RroE)J<86Qz0&*UnPYe}7bN;<7Ihw|+N_K% zxpBZ@3MPaKo>)GtuQ_paOSG7qRhLZbSSCNP?{2$c^7fddEaSFg_FJoz?Y!?CDg3xK zbKir{y}yAJ?e7=bSB-xI5B7p_#f)Iav#!=l92fUvL-*yndgFX2wL0bB-0b7EdXCL^ zPaV`{e1DK^kn^SHnE=%pH@ML3rPht<$^Y>0Mp6FP^3U8af*qzxwmZ<`_&cpWc9th4 zxw1=-SzCu0cVLElH##@J(wf;#cALz$SlH)-?rgQhS1N?rkZn`*v6i}uAuvxuBj!$% zVzn77nj;vx%v-0qi|o`bmR!Fvo&#-FUUu4T?#9~yA&-2q$SGSWhqmfQ=Io1AE^A z8Gj}r^HpSh(;GFYBU0WyXC8A@ZFl1>>f6q+o!&U@Sod7G^Ap@e_Z+;p^3y2y(A!iR zkxOEFtp9ep;?}}sfnR|lp`-8_O#ZXuQJAc6<|(aEqW|N|jY9SpFvk=l{ytD#MbFKT zJqO?>Qxh*qe|=lI%ss_7I)$s4z)Yg^TPl}3i-!vWdEvd+jdN-)*H>4FrRp5aWKu5ab59SY%2Wn*Nfv5 zZ-+$p0|n_~j5`v*=^z@DyTW$U zj<^uC^~1B@!1XIl?cr&ixMrmrTiWa-Rp9Z5X%Mu0&(il|&tp+1FWRV=1kYfLcDk5U zk)_7yvX;FS=5di5JVQ<%eSg%xUg~>yigDR}xzHS-XZZFlJOu(@Y=3_cO@bvIyz?b) ziX?h4d;2%=!6Y<)-$H>-N&Y{vmH4v`_>-KY3>`#M*>iCFQeX_;-yOY($#E5%WP)yC zDd*7V+Z2JK-pR|hfEgwd3{H|6yS3$j=!uR}`zQW}4inYT=Mc()U+yPH!8j(FxpSX% zCA)O%UG+2HkQ)0!i(*w8Ulc?r&TZa|Im%(c%rHm6f^;$YAPmcRZ-IjjB$`y9Qv}6; zO#q$)V2qU+Cb%!O&&g(w9jFX}rE+9~KHLZ(70gN!^;6 z2OIP^4M#Ogzu3_Z|HNz}7`l6kK|X|EeZ{f@zJ-TP#-%^n$Xzgj4^3*TH>x&}ormPL zx6Yg=m21}St;6w6eUmZ`7TcoqD&KaALuH>NosA-yrGfMZVdo1917rJgAw1nl8Wv z>HWpUtx zg`c{UQ?Yg9)xgAu!cGlOKU@^?xEuiv1DSb)c)39yRNK>c^c<;%s4paK6Ij4h&4y`m zSzq1M``cuurz1#}@=T^D`fYwv=0i?UXw-2?dpJkqz=7C+q-D__xzfUU2J?=c4YWnO zFwtSh$;~$>l2dLxV&xz%B_d`s2TDj^aF|y+B{g9|I81eW9A|lF^OZ+e7bLX2kn~U<7t=i**=9w}0u;=trIC8Q4YyIL#4=p8ccXyV=*wr!b zE$g>wfX7*Ol!QdCm(=T=mWix!zzz={ zQQPzg`1YDGI6wcwzS)zz7&_6 z$iul(^+_;LDV`UH7KcGwRAz~SW5&4pD}CGRsZ@*l$gx?k9FCn6k<{)Rb4|}@8@ugA zrbBHnRM}eApRT))E0f@PV7kol^5LPZ1!3>-^-qCTcyS!&y_ha+JkzH4GRN92NYh)B zN}hENb*4P0ee@I^2UI;c^vAEfJMr(=6n_I9+;@xLegmDy8Y}&j?>+nnKx1NH9kRI~-c|hH z^$CRfX5E~5e6oAgc&~-8tv=oG`L;T(H!hL(v)0tdR0?7ATEfkff262CmTNR;*rA|{ z7!bR&(rfU9XWZ>8*R~&N{>~NqEBsjguR0~GVSDuVifWpI(>uXp`N3cV{ExNz6Y2*l zLaj+b959xP@6~>=z8{Jb70C#SDuZ{9`Jz#IuClk3q+U-@;hH_7XO!sIbpj1eG&ks; z~=QLbKe@jQG9}ILGRRoD7*K zn(M2}c2Ydj20-DB<*E-eke%wsA=%9;LNi8vy;0=cl5C3QH*K|*<;3xZVIQS0H?=Zb z(%Z`}Dj1C2f-WZ=sBs^>*!Yk6cKP6S)t?{6hOH_Jvu@PqP#fxNVn_>onx*&hm&WbP zYRjcpf6h$%RgE0Xbn#Kd=Vl)_CU%EeelFeX+Vk=^knH338z}!fmF4?QqO*rVmYnV% z-u6RUzX4uv;yb&GAHl=cUpefGi)(%Z61AnXva8<{A7=irJ*BoU@$-!}rR?t@EPbl} z!P1M;|1ov>e@kuoze!zNy87YIG>VB2^($6dKyA{(FV%(h-M;}mA8gnKwXnjqguUS7 zEhZZ_B>u29`MUvNa@~rRM}H^J{9hzL0k#+Ue^7kqzl#4W{i&q2pO)|K|FWgpU$*T0 z>G&I%A3F5&!;AmywQJ7+XiGo0#k7AVA7YWy6F)y#YY1K~Ph9@^$Ld1pf99(QJ(l=z zhcMm-tO+D+t58)EJ($j1UHVfd^Y6}%|3_y@|D`o*D?xvCv2;!Tfc=2l&pB`b_+OU) zANKn@we0^iwF}q_urBlWj! zA`%~NOMKaN6C9AszjS4juRi2#yM>kpXRoy&r3?S@1_&b-*H?ul3ynFZsc1T0qSUqL zD*A-t1th~uG(tBZl=pvhST%vO+yIu91VzRsKGC<-@z3REJy{{58OBPiAxSjDRu(Hp zl$n%-Y>%QROqtjqlk*9eTMuaA8b6A9oC(SwLbHPSyUo>{EpyQxhXW1K%TtK82Gyc- zCsmr&o{4S-ONO9V5;ffpA#WE(S{i%aH#*ep!{o{@d%nW9hhODF82LzpAs2jRjmH7U z(G^)JIEqq#@R z3n(v={b{VTtHSe8Ge|S2`|!AG%chK=?N(6o_>@Z6bg{0P61^Pqru&?!CtG6^?l`-z z!HNK*8`vtN=rS9;Qcj*#9vR$G^Gm&aTU8|UAp(?6F~2oK{G}h$n3%HLC3@r=D~>)f zcBokD-SZ2viUW`F|95O<{E}8(`jVFWli}fPZg#;{KtpSq9gC1N(Q25`B++hoWF7*UGOPS-a_+kU6_IJ~{XB zG=u*&qpGNa@s1lq`?yWc6*_Lb5m*gXI-p6;}>&%$BEaXm|3?@Ird&?huRh6E*XPn=!~gHo7KpdMBnW_2aK+v zk--ed!p~kDsM;mjHg<`16hzI&>sbc*tkkcS0*FO9-(bU_G@EzFI5Rof-Z$ z*{G6#&w1>BJmWzp9CUzes_v+fv$1VkwzBQsaqd{uuZnLu!5gz3KE!C0l<$MMI=&Dt zsNYzDI&Uia4Lp5(C_6D_Ga>MvQqWxKT0-mcZZJ$Mz;fd5zn)9!b<}rs@V1}b`b&31 z1za4ww*t2=Qae+?9Jrfq1EYU*K6sej;j+A(_U*)%A`|tJ@^2g0&K>@B`IpYO&B{Ob z#I5Z9;n67f!UG|f`1IMIrD}5u=jS(%zk6>b@8-U&`x~&7Kj*Zj`1wZW@@F;hvF#&w zDZLZwmQ!~V!PMd~xcHQ}ldm9kOQecXQ;pXG{Lfd*zY)7QICE#HoKZ{?PJ|^I+pk z-U~M<8PLG>I5YjhpPh`l>G2!*(WDo zzf#n`{aq=~8r;zRWmX7S-tJc~*Uo8x*3doIWjQr!306-P(HVtvkJb`EyhdhXiaO2y z*Ij$i?jDWdHnvXVfBag?1Y1+~ZS&t5b;R`a4sH8aUiO$2#K)(5i7+-VM%6627`9Lv z295|-f#EJOqYI#^rUgLLamjRY57(6#YckzyP1X`WWAQ{hJCHA>zU}c!2FLMW5pa9aVef zcFk22TF~db#DJPM!iq@1&l>9A<+SZCsS^%ocb3Zm54n(@Q)RK*G%kA)a|uNOS?2s} zOr<2cbTpy3=I2sYKTFX|_;u>;lzm@x z?=1a2%a$+^JJzey0GVbf#0iv)?6 zx|lk+$_5(^Ipf#YsxlM~WQP2(2Lrlt+gH!sTBGK^eOdTR1N|fLW9-R0+L5M5HgkWD zEnKy#@>Bi?mopl~Ile&AI7E5$visxr&ayV75AJWD9rjis@dulOC(BXFJ{I{(`dV-Y zUSLk7m!~$f!0Q4{8LN6f7v)c)^)S~OFvt0IAQu}ZdV{UfO+#&I@@uiIR5&u*LrlI9 z85{svDAhbl1lZZOgZt&vx#|&vs;jz}*zNANeiy@T!cKNi5i6bFN{lfa4%l4u)41gB zEJNTM-ZUPl9!A0Bnc%+N!P=TGsVsP2PM`2If~d{~^aP@UxzQd9N;zXfFd_|=hlVD# z{L;BI9IhXDi_=2TRL1L8U&6w*t~U8tD>7*vYAH5Sbbfj#dfqy_VGyhTN{Nx%f?`B# z%1NM;yj6@0a4Wsm)^@S$JL73mC&<7MM-VRgOhW zh)8r=>Qm8(`~d4%MjNOgFs{n0zwf3EsQKng<){;vy5mF7rnDf&7&{;3o>DigI}Rxz zpNFDHJjb@~MM?!fR&tjiV6-0PqOBm>RI&lX-1B-l z3b9)WVeJAhwDAc%xo2GlaO&5zwuD>0RTszx;t~*bK#G4zyFzv0{6<48GQOV=xYL8-TtVJgg(bNU9dZi53hzvyo&DBsLmp^VcU%NnFwE~xUD~h*(G5~ARyxx z%dh||UaCxMTi%}QT-DN*z7ySDrLR{+c{U1;`1Zw$t9EGr6_1~RiI9B@N@UAe1XQ`z z(~Se?J4#BKWqWC2r-gdlUqy?!;u2-8D}XC0QXps`>B%*H{x4k-dJqYl55pwTIcw{F?SthsA26)E4*~CWy*g(XonMIX}K2 zz<@U}ZmvATru-xg~bbtKr2zk~bF(&3Kz3luljRg&hw_`rN#FR=@8U_e)6X#Ygda zk4Lt4c5vRO%E(|{&jRSPB>Ze?m0iRe5Pa-N_y^E0@F%(G@V!AyWC*BV#TK&f2es+q z8Gd;Z2W6}@1&u;k^CUL2Zxak&o+x!WtjkjBdHwNh4FcUylby*oluJV+sWN(pZWK?2 zg0%BC8&43ZIL&K{TDK+3Z)t@lC#zzy7NeKG8bXn=Rr2gd!G}{5w_G(edg4ZsxQmR% z=wEoH;bpsPf&?4SPU=`HvnHw&1I3Mrc`tI6kt?EWdo-A007#}us>kH-p9kerVQXhR zlw+?wlK!$`e`Cga8PL*eUaqZlVh8@3XF+I&Hl>4UI)V%)eK*bhoNV^n|F$vBP$U zCtzJJ$q)oWz1J+xE~Ch!fPy4aCa0PPzk~<~(!|?p_+d)VlyU5=gqpX`XW!Di>g!a( zNx1OAbYV)X*pMDY>>Qczt;TgWj{)br)Uwj(01l(I!9U$jzDwqPA43d&5jP^e8pd~Y z+)uGG&vbK7b$>h#*w^Yc45vg~dgb|X*f1;6G{Z`_{!3zw*#>LM2uSV;!} z(IPd63m@q>Jy};Ok3@VCd*eCM`@mB&GG8HOP*GaWMXMl#$!X3e8LPDT&`%em{G$gh z-HNdpU56~z6v=yZ5na~lWM+IDzy{Ck2$9WTZiV{8|G5)D3DhieKG zWS(J1iIa@(8+s1FX*L|0_wwDrPe;{atDGX_U1ONp%+aDaX?q=KS+}9&{w2li8A8Mo zxOPYV1`OS_S6aN?q&8Vp+InYN1hj@;Su_eC+EfZ&pN}k6<*#j@tZe49@G?&O&Fx-Q z^PB27CF3&`^Uaq=JT3tScwO9-YEF;Ab!^@Vie-(ltEK6xrBJZ1@T~(mn+?*uCK;8- zjja?|4D#wwZYl64KAh`r(9$tY@@XpQ$=@noo%T*1-p42x%nSQa!CwpV!Zz)377qhD zg;A#RM7->K=h3?4fS~z`4pcDGv$PR!wuQzD22Lt!94R_8GQ!}=5tPTUXpwp+I)o_# zS&N|{Nn_gJX3G0q#{@Atv1Ro76)B?UcWl+24iqy4u_D?G-Huchzz1J!9gZf|NWkAh z-=_T($=|JZ$z-gr2God4|E z?t8y!sEDcBpn#!^vSf->bJoTRLUG*(x$fCXtVF%e%jdyZGcAY*$B+RPGg~amg21L& zVYK}_U<`>s8A;6#p)B)AU`(0-N`k&FcT*4;-=jU1B+y$q8YiQcGMU`IM}-?QF}T73)dFBcg+^Dv)jU3+a#5demAQPi2ouV0>6th{qC<;bx-;s}6i zRx2*gfdw<=^jrZqUZdK;rRJ<-nCGVQS9i)rI_(5p30-3QTuz-2&nNQG@ z7|AmJ(Wkm04aG6i3-dZJD1ZNJ`WsV-tef9om+b!GN%m7l zh(#F|T#w&<>xcX6EC3aQ>Ob(>8W*{!EVj;FHZW`)czs7o19h?8pJ#STU@#uSb-&L? zn-HY=_K}M?pbY{y4}iE)As)+KtyY_NbXH{R>gS9jqQvdRihmm9k&L3OU;!(WHAKio zbP!dyN5`1-I%W1ppZoPju1CxfajK0TbBf6oHBTWv*qVNT#K22_10HVQp-Mit8#y;Z zuNdru@CJ04sUy-S1#J>;oOt&W1b)RR1JHAJi4^rhRGSu7JR6rK7w~#o*ns$6n_z_^ z`7Ckl=#8F_QKS*?Y;Kz~KAfKUHbi;Wx8+liNo`71pfU-5&tXu45|$Mupz6*U31;*T zPP7MV0ok2p*u^o$`K5GBuR(kWBh>Lo)?*HhCjmy(5%Yo{fm&+vBF|0sOW7ep&6WOA z9T?Tc!@+4j6pJ1^>Yfm5Mc8^#A3uy)x%-y0IQZx!&BFnksm0ZsNGB1AKT6|^0QB<%9H8Jn*VCNb839o0O zW}p-n8vM4%8Ce*gD+8=~$^UGhb&!N#MfLQzm>C_kM}6H>Xap*f!V$BquxF)5-#34- zb$)i|fKtx6FS6u4Nec2VZW%s3>^;={^rf{1AJO?x(`}l(anB#y&Q{Q*ucMEFh*uEF zlv{&%s*xe#g@vj%i*{WVRtJ78-XbOoMJ-hXb2(miz~{I18V$?j2Z-;p`;QxHN-t@o z*AF^jvLyXa2D$iML?Y!s>6s_=23B@F-<28jBjWIh6Yq(CxRDCxZV<-<-tVh`4h9rH zE|}A2{RpzWGIBY%>r8%d=6vA0pC&OTVf#aEBJNp(bKF0%iToS$lzUpn&N&V-S;1O>ZF<~icO;p&;poyX7eXZ#$Hz`FfDV*gRD!FWXXc4n zs}*_4JyCY#Y>w&o=i84z5vJZ|`ejWS`sJrrBeP$FKT}Pdwbx*h<^E%8S zt?n9rDc3BbS@zJYW6rsW=Sr2AUFOT16VI%60c)r9nZuCRh*jI&jejKPH~j+Cx-OkQ zI9B7}Nw!t^ya+EphIx7oX0w#k19dS637%A@(?PO}CEREkR!S0Inc=52X=#-7 zCT*UdB?rKZ)t-3-L-Hl?h(uFPfY_SmGNbk}XFLTeNTL@AI`$CLEg`BsZ< zx0TG<>34)v3eeoh;le40$EmGoO-N>7VvQ*wr90jAOk4U*;3CsuMha zYo#C(45O1Lk!h5s&gH}!9LRc({p@vp&tlL;6q73J;p5LK0~fTm%0#&lRlV0cA@Hle zf!g8%`@>CU&2zX}uV7dgcOkyM>;{|a!uL7#ID;iVN48dMP@zz*1lf7etM_oo2u*0g zUiQzFsUKcLIr~{MxuXJoUe@@O1rj~a^{SH2LiZc zfHO2Yxgd+kmxOT@WWu%aEpTjEUPtpaOmgK2QU_bivzYF-aR)(3t=9w25q?&uERACQnCznq=kV~-Mk?x?uT zp-@5(JVIbU7rX#D{%b!uW!-a8T5ll>Ww1RaIy-UG&Ur@X??7QOlbnVY!C}Vho+!=WQgvUjYSKVu(NXX-u-KoWPG*wb`(L@m_yj$* z+ozI3#1jM(-zJivpg%<oL|Zc{#OHiX%c+o%#C3ETPkWc< zdT&F00XnByx_!gd-*;@0d(Hv_9CqV&#!dmFzIlL1=QE!!9k~ z7B!A1>OH>^OqC7}63#kx0NJ!wGxYeD3+ZsGWJ@vXgmtLPio(bWxDljTNsr4g2eoIy z_euWL3;tR->sACA|Fqj+)oFdjiNNk(H>}nX#r>4qF|BHMtj})1j$2U3Y}Zi6{GX0r zJ-f3VRU4%hy9w+SkqiV>-}F8ogp0HQ%mh6Ch{5Ez{c_0{ddN8dfa{{47W*PRO!J#I}o9@RGM1ctU^e{nctQmflWg7e4cJmS7vjZMVE66yU679a)z0j(ez_ zJJhz*0?4;)S_hwbBnkkpAbc-^8fhiv6FV3mlj?)0O=YfPS#Wbk9KxTSdGYFd2Zk6Y z0YpNWeLyq1-XCtqt$5UQ4&IGftG_|jD7yuJ3V+S0O*qHpTxV8En`G1fjB{uKvI_C@N80+PXADt#5mcu*&lJaC#$!7OcP$^uO z-m@gCxXbLUmxzK7?*nJhiRFRgFLsDug(H;PeQVTLzXgBsKPr$}&jz^-Zxp^0oG8Q$ zjIq40mJ@w}=EzcH^WTa@K0>9|o3F7#dL@AQYeo_m<1n=;{&X5xt zXr-FG#gJo{(2D~geOFEPEGRsq&m%)XiiP*yHWvGi^j#BMw-b8O-1A231W{tbc8}|5CozM-*mJ*#oa(Ia+5ufgrej|#{6IW0hHTz^9F^2Y8s*IN zdb$$cusOiEYr#EQd4I14kQ-=mn3Yt}R5og?OQzb1pG&6S~bx z+5G$H4etF;KK5*h& zvE|;R&MYzDP%%2>waMMXL3z=W!%G1+Isp`k4hvDeo3HYJh-Up8coP0=*=l++4N*;c zWG2mXrdP~!N~lpz>{ZF2EiMS?1O!5>R2#0elhm@}?f43g=GmEfMjBA!W(UgJ5MM=} z6gdK#ZdHB@ehm%Z6|k{Sd$C;IY#a!YCRt_(ci7Fknt@(--wP7!b>V7;YbR+ZcdD=R zl&8Zng3lYfj0*?Yrs|sJfmBMOV9ZU_SG=wnBnZ$}l0?9H!(JI*?_9MGhxDUuQN8DDPiXi1Efai%YflhY$sbMO7Mg9*?P@hx>AESTrvqVqk|<_HR9ZqObb_3c z(*1ae@n%^34%Be~=x7VOg)^*kC!hk>FqMV~T&LKT`t`Gc`gHTVvF(_f?`C=uwj8fT z8X!im9JjjQVv{-RG-p4wRnF27_N_hhao?qY6;4-klJ1 zie=Z8h2Yl*h_&`B?zGkJS%*@%a>>|vJ}eQwh=I&+X~rtvpFg^PS{DrGS&Sbwkcn#P_XI5{im>f? z*~Q{Jbnj~c9D+v4MRmf*-@r?ukxbON2I+PkLbszQU+5BeTkTCDe@|I{+-$Zx>T$@l z>n5qk*-USt@-Bb7p(xP+E+C%#+_kG$qy@;b;pHk_RxDjqIZX0CAC~P;C zINPNwiI`oiB&IH`cl?wMM`q4?AABDKiO$mo=^u|7ttUng%NMp)qrF{FVS?anJkZg) z;lPZPH={22TIYCHd~XRW3goWs|9GTBQ^Pp%U8P@9~?gbMoDdlHnVbKEUi%J~a$~ zW}4~dc=K?cwJA$4I;X>&`PF;j=w2_O<0&;?%Gs}sJWu!}5_EmJ{qYX;cxVg+ygRcR z_NC}_^PG&6;r-`8OAjg2r>E?xUr_>8x zM&n41INAODaSq~fX;RA~w(NGs!^(;$OVHYIKVk<{97b`LRSJ2!I<`BgkJqr%`$)w> zjj-Blejl@_dlewFjK-JpSD*O<3E8v(s-|I4Kog=m;n!K%(oIWk$g- z!)<fFwZCE_ZmFZ$;HgqL=|IKD!mnI>bV7UG^v9MFG|+Xil7YbT3y}_CmgL zoR{i(cu6cDMv=hl$8^m;XJ!CCK!|oyx0{!34p~|lNc;eP+ENK9FJLDas^&zzq-#%J z@hV$kUH$Gye0HOQ=m`rR30|B7v`s$V-}vQrT>J~3x5B|^@Pe@tT8G=mnS{cJcg5d+ zO4wj$b|=KJdwrUnN;>Y>y*n>^x5!l7ew%VcsCRsRO#12IZfkfQYT#**WMt?ITg6T( zof7Il@w4!((sKsTtYok7EC)Md_x`8niP!SFB(Z`tlng<&yz2B?Nv5SHVpNcuS9boe zh-2KP%c9baMe$zIxUMLm&D8xelLbKrvb=A~oE#`mxzu_+=zjEaL9LNy;!@^3rsFEp zO%K*(Hg(lRuIW9^e>{7cE2_BXFvVg_Ue8iGU4|C#4zz5$(fR?g?4r6*{wqYCsOIa> zyc(u3{2Opy^yh-ULf6jIca!Rq3VjbZnxA=4<9`0y&aivy4Wyq8E~pJ$rr+9|Y2#{7 zaeEqsYX=sJYe`vHR|!O0eBVUuW}|CDc71eb`IMgXX?Ss^WhD0J-PO>aVVdj2Eqz&b zKJ^)4nV%uEFBM<50bOyG<#QaFx4eZu3bF0ofY3Ih3tbK9{zdH@t=z4tS=d&I;a^g- z);$<=YRF2gQ2(~(mE)lg?OL)~V<4RkrD*Z_k($?fG+Hb14Hp#Ft;3>f-?q^q2M}qb8DNGQKpN>GgdwCmR1hQuX^97hj*%`E=}rZt zLpl{Ch7b_x4ke|=y?B1_`+ncI|Jr;1u@}c2EY`Z$F!$7TU*~n5=h+@Z(F&|i?|({uOBG5K?@a!t?Ay31;8HXj`59x|tWTh&SXekaRv44g46~I5iaR+bl4uGFWEN zw8g9)!~6Fsq4@SJzGW--MwK5OKyJU%U2m4^PC}=u6|>i?z3|$9^xDmCp)h5{uC7(W>FiPKb7`1`sb{u`)V`s& z2SWi+tXGv!^I2314h0Pj;u{GVu0vPpm#{`ce-4avmS;!sD{!U5l8k!@bpugZh9teV zcm_&p!_{owBQH5UGX!&w2<74)8dfAI>u+*%=Wg*9Zh~TS*411%M3Xng;nhZKOa7Ba z9=$2k?*URjGfBV}XK~>Nh80di#ob->du=X>z+qK|eiiwzX)%h-+1b|_wJ^6U4GK~8 zsQwQoB|deMrDSsY&Bk`&7!vi>g&X*!El|+(K$(|##k0HD9o@C3du3yi|Dx_wzsuQ0 zv>F~1I)BZV^W26VMCGB-Il@KEFrYCu(M7rzPe!QalpNX|_NLCqpSW0c$oq}4u3{II zwxM5~y*3u9Z^BhTN?HK3ao9I*>{aNp3`xKkQ@?lJe8`si!r*PFUUj+Xs1Tu?V~Q++ zg4rs+st~cqFvc^q1_YLoXPA$jC5{ z@)m#7y)9S$|JD=y_xs=3ze^wr4OMkj5DpFqgaiD5{?3DxK}3XvU_t^SFc?fsOhiIT zbC>ka9a07=YH}JDMhGhlBQrA_>^?Ue2S1dVndbp7zmTw)m>7gxN={Nl_P(f?$nBlr z5EB!V-XW#GdzW5>ota(a|Mm8_6GTab55foG;c$R(DRJ;9asKv#Ai(1!!1;Fr{nv(r zi-%7@2qq#XxdRNSrvTyN;Njuo;}H$BJB>(4QXUah zsiuoofBY9r^qEH}G08nTdIm;LE^Z!PxR|)a14$`q<%cS&NHuj014AQY6H_yD8{6l0 z_709to?hNQuYCRd!@?sXqoQNb$tkI6>2Kb?%g8S%EGjN3Ei146R9D~7*woz8-P7CG zKQK5nJTZxxnx2{cKDWHGy0*TtxwXCX`{?-O^z8i4#pUh1aDaLK_x7KO{om$A3Cs%@ zA0H1Nd^;~3+*iO2j}o7NU6_zcQ4ehGPR$__LPVpKlvmS53>DS?Mf=QSoa7!%Y?<@- z?bQCA+5fYNh5mn<+5b%Jf6Z$SM2d$4ym)w&AOxtU@K2;We|V*4u+S~%+|)OH2}ScX z&7mRsNVvHoyUx~1&)mT8Q?7mi}myM$slz8z>tx8$OmR`xxTY(}x<$sV|Ds#|@M>pwfivN}g0VE_oVO)6<<%KIyqTI|0yHGFGwv zDiXq#&i5_uBJQFh~@TGUhwO7^JKMccv{u0~7=M`0q39#Z9hQgc6CUgzdo* z``d^PmS^vU{K$~Y>SrA8QIO~=>yRFUCwuw=)^58t&R0G_JB(410n~<33vjhDrBGOoWUu_0hzb{ZbW*p@zjFsHUYoeo4XSd~in-aEg zY}!lF!ZLQQK`x z@)h(2B%*NOzL=T6VmH(Nyp*AU#S~8=i5y82+~tuMY;Yhc#$*JB_Xe;!I%0eh9upkX zcw5OAr;H>dWCnTDOdo|L7DbhAQ~+K+TVV5gn(1}PKGppaMXQU)b+dDs`W*raTy%S2nf85o|y4jcU#1EWK2%rYVJ>P1%UX^zzm-^vm)^chQ+k@phiW+t`;$&$!rW~WOPXnQ7z7^`B+ zCBm`;Zs08CJ4V55u@nIqpI1qXILB5eY}v?*(+ZJ?W5aqav6KfghS!2=2TJIdx-qmg z@KO>&5KD!~3|0wTVqiWfRas&E`uJ3=0P~INjhtBPo1Zt zBa3L-OL3(#3(0yyaR#Pq0j8R%e0_yTWCSMDmer~5-gvSo4|qFax=fw3Y$!Te-$cws z6^b`k`BCHb-b5*r6uviMa7xIx9lmU>2L%$fj;3!Q_L}%hq$eRuPfFzCH zW>|(ry4dm683bUz>6vSq-8)FsV0jBt<%YEskv;m}J{&GEC-s#Gz< zq~te*MwgOK?uEscx{89Up*Q%b@XFjjXShs1Ws7z6@oO3*RDDU=b?KF*O&KB$@m#)Z zZ+$j%f~0)rSHcRzr6Fq09dD?@kn2n(fZc}tIh&0R+jsZJrUsS+gWr70v08ic%-|GV_-ViBrPZT^!^IuoM&nQZi0%396i8Ox86sGu-)4VE$rG>5=l2=Jc znT_7@+#-ZuJXssEP#v0S7l65?zepcgHMme9Z_`-@T!k~5dCz3OCBxc>$)WUkNntq}{aT7e3w{#BMy`d^(ZdM_6B|!Y5+oeKFzH|9 zxuDexOo71!5p=J#T$Rk)lJWp-zRB4TAoJb&pLL6{9dhLhec^5!%#3*v18e&uej8Tj z)+|Hg47pzdG{Sf@LN&1oos;zLpGHzr#hP6m+K_fd)7RhV53EffG0gEl6iNwO%gcI- z!gEo6X6n~XAA;+u7&4~NqwNY?J=?mRBk>ifZ4HVKloYxUN{FNnzU^{bKgVd^%%f{k z#b==BEe~CGo;5)RV=-Z7)reiOtF3m8Tq^{HQ$PY)&liiYvwKxD$K`j6G^uUe!HW&( zBEg8+x>5wkx3l8NO~Q*6?z*IEY<7Q%vJK)gOZ$7w)}4?`y9)DpeE0U(tZ%u|6{Wt< z=D6r^r@oS^qXa&MdS=UzIf|v!CXJTsdai2~*j&lmL0WlMr!2&oOczS7Yi0e7pLaxw zy-r0u?`Um!n|+7EFbIVAbGo2?tWB$^*S5YRV}*V2Xbl$f?N@e3q*GvlPFhFX91SL` zK;WP8@@GjpUtCj8mFGi;pZo9iNYr?;zi~CDO28I!kf^iftZBIC z^vipC+V0R_DX+Zo>XaA5=Z#zgxk4pG5#aqk-aCCcef&2h+UOD zE7Vo>oGy6cnv;2*U-|8Q8thRMb?GVFR2=ev8#84Mn1@lW#v@NE%wuGro6T6G@QxVj z@|340rP0d(bw^6RW7+8bUT%AMpF6$xo{nyy;-2GU7Z7fNACz)#RoHg9NDI*_}t>a?ox)|W9XXTXR^;!|h` z#Q!M*xxzpqe)9DqITCU7PZ!m_`PnvVt>`-t2IfQ4wE&!-aC|CGxkKw+p@V7rxl0bz zC_Td$HRUCl31IOExO3n!00PCx10wbsXVT6Brgn(K#+zTL{)8U@7fSgLZ}GU%OVLap zYG(C|G8&hs7h4^GI2wryjoCR%+kgw?=hH!8ZcHXvf5A0W_j{FlfqmBVhNv$p*9m|0 z>QS5dSmZTtou2&yzl>ADg~PuWKjPWBfb1pw?&AdRI@I1F`w6)|MqTZpB3Nxv$D=y8dlG2=(4NMDn<2!%<70p6D;_p62hjr$ zwDvC8PVf+*oc%-oyWkwP`0{EE6$gyJ$MW{(DfR-gs%nEh{tNmEy>_hAv#Q=3*!c@O z2c9fO#H;__vp&>RY3uHOL^u569yd!T3$|V*Lc~MML}Ey&7gUql+B_sSNpQDNzxTXk|da#_(2W-a!NP&wD=1- z152q}m~6vpjorqEc+&oSWGCExIye4k1E)t+u;_ttly@B+-#NxA#~e+3hi7PqC)^-z zPL4qJeForThxnB!i`*b3Z&wo^ysyfjk)x+Y(Zkcj!#$nvA|m1uOk!ELxYK_SL0=UU zw`#NIft-GKR>GZfi9y-eZmU_j&sC`s>g)P*xO)WDfOi#ILCdcJ<;3?4IzP&AB)gtY zyhqdVKl||11SkhZhaEUR5_+Ht{#}j+)J^V6hRhnf%Dub$)Xwxuu4xCksi66Mr{}o* z1z;SWn2o^*wsL=e&?@$7j(i1@#TuB4Wxtr#i)O|25XqHY!OpEuZO@ZFomFU$0IPut z*HM&o?-962@cT{anec&lM3krP4@E%x!Q8qf>T2`2GVg_sjn2K2vGKk9mV}*?83V-+ zD=hR_ul}}JFT3lV+&cNlZ2qo2hjldhb9Had2g5Rrn_5@CdltuqR}?3?W`adB3feTS zQS%o&KeHfn;HeJjr#0L~5F5R@*9Pp}Z}YGJg8a(5Z(8pa2d2s075tv+BUXhQm?fbm zXe)O||Mj-#=n9-2#3Fhz*_PvZG2tE}Kgx3Fj?AzSF?d1O>RtS!-XO_R*&HR5v~1)l zB1;Fp)w_M>!zDx^A5aUf83CD>m^~g*VzU|Gii)xtDoDSSP%a3RdX4KnO6>;Gc(eZ+ zbQhW^M^p)z){@ccOuzf|jloS_zAl?Z?u^sQ?`H=ew6p=^QleMWAJimvo~45maydgM zP|!OM;6a&omGg_1nY>no-Y~mQzC2aWoT{r^^z4yhe{`9^P;r$*-7-+n+tR!R%TP^H z8}70)Mx59sgIFjF!z435v=Y7V(@9ZqL~Hnk{huTFd~d~=At~|^&SOfwEo*%W3jr+| zq`iXYV8t>aj_kBVjy&hA4jBF2_yRf6v|C*0y*wj^1c5awf^gz=@&>kz9~e3JyhVP( zyWWMr+ElG)KakMNj~&lAkR-^Dy&6|k<0<}BPWp)e9Gikp?BB_Irv}c0qP2>eH3TY( z@`kvhpNj<7zwb0BcWB7NKpdXUNb~ot}@ImdDxI-3^r=AOGNhkD4xPkR}I(RcZMxTlDa$zg<Ux|(Zgd@+kMVtic?iyJ<^c(D%al~>`?mf~ysGVT8tLbS*34@sK-1Tt>{bk3q6pvp z4LsUOHd!*oGjacJ%j&oUm{q`(HhkeX-Te=O9)*5Xo`+i1)8{gKsV{t$AlZLx<{OY_3xVh^=?Q3EXzq}eRmMo6oivkHuRwyQ+~+O)EqWr-qIme~iWTybkzTHj8(rbhbR*qklC zkD?_iUmz+B#jT_4K88df*gZD;xjOH129(1J!!U&KCX@KSD@KXvZjCk)+Pvhm(U4yg zPh@=Op(I`->_+R+Tzf^ov1YVJbr(ShK1A0^)8fi4PoOX+$sbPPeqqqA`8fY`O>}a* zQpXwR!O{*IXV26wH%IkzYS$vo*s@WrNu6zeUoYIH9qU-5QLbaT5Tiu#eT z<5YUfmBtoa8dV_=N-)zRSeTaE!HE+`GG+<%K4y0!Pj4dg_uv}uFcepr!YweunJbAR zZndHoCNVQP&rr2O00t!kM$yzG_Q*0Py+_YJRAi0Cd2N)v(u}u>B zddrfGPBJZ`)yn2_o)b>xw3Wnor)~vk!p5$iT4yE+$LZLKySHC*tdFvx6=oSvK%w2K zo7o_#yTH9Mnn~x*w&8McIIYk2U(opPM^OaeiBtgcGGA#QBxYtnuO#J4uY^v@!b9JDEy#H2IT*IrGw}wvm5}i)%9VMl zy^*54<0fO!OCn>?IQ}_pO*8c^k)cls(VH=Szf`|8`CsiDvZ{4{&fAZU<+hH=tN7IT z2QHK{p3wkjQvvqh`?=F7z)bSY> za4WPfr{P>22eB!&j?N))RN+i)YOk{a46`nHf%fglS0Slzlz1O2tjwtbrNOFS*@{N&aaj zzV~L#gAch$3m7_~Q1Q(XPrjr&3b2mT{>kf^z|x6V<@QYWP%uJX#O+)v&9O zeGr&x?I!j~&SvhQ*B8wzLpo9QV2>g<;(qtcjgK5+YLx15LW$-<=&sR=eny_FRq*U| zZbY2Nvl_CLSldh1Gc83-o}bL@QGf+g#kPcb=TY_*5^u+!yuW1x(xu=010|^KViXqoTeVuGhrH1E*vq#aGfXJ6vI$bh3B=}N~E6Ldh?YeSI?;-z8ID3K87~+Pr zfFy~JgSsJ#bepE@W<_AFj_1;x{2;@_=d?YSz6 z&Hlu5z4Yw-@C-#8j&E+3kE&-Mx{k0PD%-h?S8ChK`4OQ8$t@aQtlW*%d!m_9vHs-c z<@IQHKfH$*I*NZxL^33bcpPD6GOf6xChRvG-$@7~pj|Je)bd~ydvZOJ1 zp?LSKFVG(YmTpvyj_s$CU)m(|UZ!Vxdi&h3`_4h4NJUJH2W?_wtur%!#4L{4tNKA1 z&2TyG-qyaQ8 zoZ(V8zSD5Oa7k*X`qyq)v(aj&lGA>qN6v4r7>JDZ%!79&{;Gq2wKM|bTX&(*-ceM4M%`%q+mu;FrsF; z0CID$0*Cm*#~PV6%C%CZ3D^JRTy7xV<#U({bEg2|H6aDNgte>Ru{W0ed}!T+m4{v? zY#Y}@nsN+`Q0ps*Qf!*jUl4##+(ui?p1&Z%GQ9w!IBZ~Z!{R*^nF5uV|9NUwFCs zbFu%R%-j85l}O4vL2UuEoz;tJSA*CKOE2-v0(wrG1vFJ*7k+uZFH@qfhg`HAN}BSS z*PzNdfg5t!poeDH>8TD=zD;88+Q-T1QcEpgA$pg$*~z5tf2LFxcUId{{odCKC69S-YMe}k*J3EU?{I!(6xkQytM|c?FSkq8DBqb>b@+i65lmzko}oc zR%RjMjJlUo=C61)c?&lnrXjgl!`g&J;8$HTsuH1iT^ciK;v<6QsgUYvry=>*LzEN< zp7=DnJpTsTTP*$GVEYP)xVH|Y|2YeURYLkvB=MilN(;3_cK zOjHgr4h17MIBKKsuGwCVAIuxjX|T>@7mQO>9%&BY<7qZ#WCa66y|(`+ zQU#+M48yjxQfQFDD2!%S6zf-V()BGstItlH@uiBrS1TK&2{-bj{yJE#f+x;Jz>fPm zrlwiUb{x$c{kZ>)w-BJ39AUj&`s2|ELw-*USK!vSc4UUAMrYFfodENU1U(8Bi@Kh5$2^pizuI!E`D*(#b=-&F$;b(>c3Kk ztG-cXQFAxJ$|$S-_M>376qrF05|A7ohULeJoGH!DJ+O?%ZlFnh?;=7b1uEDfLK!B@Ku}H2uJDz z)=5x+}B0?+Y0W2XQ4LmY9I&bD@UJ6a_t!Ersbg={3!T;2^pE^>c@Lo}*Q0!S)(!&ZujDjL zok-vkuOQxKZ6!pwVPj+E&WN3iM3+;3lE#{ud)g3byk|) zj3=fgqn-hTZft1Fvs9zpO8?mxcb{J~`W)M9;s@!k(3_@AEv$;u_MNs@BOE`YMGzrm zI%^`%F)dSv2VKV>3gP~xl90re3V!`zG=^5HT+} zxCcYk=Rc{rA<8PhB+xifQ`OLf1VW#nL{kh`$Lo0`jfbtb%zXZWWQ}IqxXXtX9aa~5hV1!Ht9@~;D)$5N zeyQX_+FP^!f_~tj-iqI^qpTSDWtg6Pl@yk{HBvTgmx?Orck}CC-99<}&^s@yOG&B_ z!OUUhCId**&wVL0&o}3l7#2s>sPNzMi!W46Mliu*0$3p#~_+z9JCrR(nqb8ch| zHxkVzKaeCP|K|*PT5<2et8}6A#jel%%c;u^SLo4094zpi=bk zv9Q7mi{!3hU5c+a@CnVipY`Ym?*oM6K~d|$$e?&DF&kb`x2n)8-uAZTRXI}(DRK>e ziEIkrUnMQf!nA-W*NbJuh*7tAKH~JiQ8i9nUEG6Gc8C{= z=di9Og&zp7!Wh#v;uMFNTlb%kGW~|;e4UP@g9zcDjfjOMq!BZKRvUB-EVdqSjvVBD zz&Ufa^msMFC3>zI!NdgAD_~FG>8d@-`MVaT`=k1hFfDTKe2KT(?0Lcn=*QPsLL| zOTJ&8Ie@3#OLs_jFe4K}K2@HbG^x@cbmKEwh?aqZV%Yuxb#?VCRPkx)t8hr=@e_9q zuR(emF-9v0;fVyU6~(vtg9p985M=fGWej}kjND$DE<&GD+neCA9^=$$-%90>lNlLU z3(YOnKSPOLl3kF5BKsE(wPs&x_Q%L`%O@1vP zRV#iYkJ;SUn}X@9>8@pmzHvV*j<2iRlSpihyRRiiI$5J;Ogf(7t6-SzK?Y}AXh5}x zXu6pv>+-}B@@C(l;D!v*H9PbPJz^gu_V(!WL%!h5#*U9A9X?{7SRfE!D=O^Ia01!@ zNe$W^i!-RHaZ_;=@^{X@){Y7+x<2`jXf|=2E(nfx*7?svcQI~eL#6;D* zrurUI<-0S#OT_Yg@d?kj;B%h`w78O6AyP~=*?@tZsH>_7xWnAea+BNbz<)exK$bOX zY%D!A&G^UIst2t)+>Ov5^HS1bsv)V#jh6*yDI{$E`mBUs@fWD4gpD=a$V@;ZcVW|x z9FHA8>Dwd5bRpeHIZ-q+QB9e$ERkPLYSxrFWM7Zr zHC{-_AmMHZ@my>(-!^XHOBamO$&i9&kB!{)w)|E z!Q4sao*o71rcYlAJP_i`uWi0EPS%UJZM5pa!~*rNo$xtRDWL}PbBmHqJ#(>!2R0-6 zrJWW26uz<;Lk(xGQ9tXQ<&7fFeA{$-d3d5Xp%M033(Mnk%cN{DWVm@m5UU#bjeA5F zC2aBP@bmJwj?-_aA9#^J6H0dc&Ga{Whf6+gAPL&&e2x^|(7ziAbdJw1r(vI2nkEjR z%@ZpY$yJH9YIF_<`jaK|PG_~Bmb*dVpH`wXCF0Iks`J<&C{R`EbKN@rlEth^ zT7ht=2iN_ko$YFAs8^oSi-!IN0i20&U#az!!0BSkluS*MH8*&l3S6!v79SD3@Qm(MD>kb*>q6 z6)b-VNPgbXtDlry5Mgt&|0l>uXTKUK8hYJMU2q;)VPpgST!AFzzJ8OhUc>3l6O)rU zBIotdTnT%Xm1IPVLhfUm;w4ssZ*Z;h0%F4qgXSUEXMlXP{!Oj?Bp?jU=clB<@H4qY z=Dm5X#SMJp;8H?uHNbm~_k~q{PrKiJPO}83|4yh zQ#kUBn8_vG7ne%OF12-YVP6kCT*wZ_6niTvTIXmNCwZN<$XMtd9nTLB>}I63$qJ~h z26V^*T-knjV*|TUvi#DK;fUue3znbzS$fz698jUW(&`zNQB+Y-+uhng6Bh znARQDXfg$#F6$Epj*2#unuQ3QR6%`m@b5!&bFZ;3#9@~$lz}CoO7oQ`wOT(vg$_ME zZu68zc|ly={q~nX`V5}@HlB8Nc*~S4qKzX7MQFU&)x6VtH{w1a4M317VJR<+#8;XS zd>e4UOrCpa$a;w2*Psjp;azxD(aJmWTCzuG1#q45i^Y&!xCfK}gL-OUpcG+{tuBQy zFT*8zqbipXGD^7gD=<3($g{cmwqR4Qdo5cX9uTdg6$1ta4;AU%)56+vZo%weFy%6ERE#4m;h(^ z=gbmBOP6}EJxiJfXqqV7X2+9L>pRM!s)|cO+b7~r)~G`}(sW)*9d)`9LGgu_Zk%j$ z-~`$l##=fZoSnx>=)tgbJWgcO!RMRuR$|5eP91%m!OO4(!_RsPuttw$K`3|9e)j6F zj%IYx1y?MRZSA89cQfm|18HOUZ-1xw2yR;255`9uavG)QvXc{pYX^4RWA4VJzxv&9 z*ZjRp7f*mfbEY+6w$GqgVC;D-T3dyyQ1RMQeh0Z~U2J;)G=bYoQB;a2e z5`bfp)1$_+0)ZVTSC#AjRflhj%9!~40^geSCx)4sC}I6z#oJxkoKIs;aH4UB((TJg5jVba`of zUD`CMX)WhiTu3R5x3FZ7mQ81)j1Sz}Q1*B{*hec=m%{ek@4VzSgSL=Kj=#41V>M6o zcx}sBnQ@_ne#zsGkb>doy9uLjWS{gH#5KZL;BD<%+GLW4dXhtOD3Y}1;gxwdqFH<# zMSO4NKa6i2f!Z`j!doBkwz=h$86O9TMnYk8ELL|GBDCepQ6!^7N+e&`9qtVZ6$&KE zUmN}LkTq6Bt|g&JvRK!}RdKj_hxe_pkg-&3PFic(iTo6Q7+$b4PG(5gCE7$<$i4MN zL}mkhFuhwK`5*m{Z2n&Or{J+GfJJ_~O|!Pi+UuWS?ymKA748d^295j}wVs&Yi7Rj> z6P+Bp0@S)Lz0M2Bg55We@nAPZl_V`RED3mix$~PT^vT@ZcMa|ff%bUTNc|_<@>LDP z05wJ1gL-Kp$H&8p%An3jP#A_XNejL^1Kr^v4M-TyJ!zk=RB^GZ-l_14V(4G;#}y7m z!0V;HehB=ncL4q@U&oy2o~&grUey;_pq=_Y{*C1BUB-j`FxsPhME@!zamTr^eoSoF ziqY*D=)VBvSRu;9r8~qP?E%HXAMNFs=k%pNl{ef_W>sIJO88WKAOd|^nfA}y>-d0= zY!~;*Mt*`>L-U1CU4dk0bW+Z6jeVNc+Yw1B3eWmx{D5h+Z@REkY{Oo~cSR7%LGrfkJ;9GayrD_@lg+jq zosMuHMcj8*d^U0F@LI>w#iLTllE>uIl^%Lrnp~#EpsgR?zWec=?w@CKDqr2835JO| zyXcSHk=Ee1c6u|B-~M14vx(4#j&&9nRT~48YQ4dp*#$|LGYD_*6)mb0iv`Pte%v)W zm*Isoz}-_tdh}(Q+&`me_X=@eL$UWgV`0I^f-~StL!^RoVk5ukPBXS%Uy#9Rnwa`{U8AC3 zH{U&me4U3Zf{No{jS6=5#-X-BZ~ znRP|Nk|$F6vtF;0?_SU4Bw5-&g&RLQaLJFvzZdFiBisXA?g#LNqWCAXyVw1Wj^q?a z#2@2+VpLkWSXL=0r>73}r6gV~7x?ZHY#U3R@Q;yUV;mD)c#C)xjzK!^koj_aDzh&~;!RtSkuekEQv{$Jsd*Ic zfD{MJzojv9v6`|`kNM=%x*3hXa#Mr?nGJNJHq|dZT$^tElh&e0k!dJV7mKHo(zvVE2@t;$$Vx>*4Q^;K+fGP8lA0Zv;J@x>O&;ugkc{^<@8W9C#mwT`HbG zec7FfT3!1KYC>c=or`KU@x?;_lM)C03EG!0E=$6uK`85xK#kWR=vo_1elAYp zY!GwL)O;$(ae2ID-&H~KfSe7(H(j~||26nVk2>inQRdSA8Yo1SyY?FRGYa<~4Mg-W zNu7yjyKXeL2tNYSKgFdR#fp1$iEa5xt(G@SmwQ14;!dz_@6F|AL-x7Y@Ac>I%16 zG>25zQ4GT%v`7VHwaK;=YdDGf?1gu~Dm_(|-Ypj^XSY?Yr)U|2|4t4;5WgTk+B={KV`zYaBP&8Jlph^2t@* z`7QBUwwB`$@*ll{aZ-mAy;1>feK^<>EIuMj8!?UQ?C8#g?4XvEFEFb&_Sbi=;qOvg z$gq5<0+e~u=kp~*BG8h6{<-yYy6|QDAM!Q62hDsQME(zEE)Bl@Kqx+WqHJ$7`vYzH&ua~f%eGg1~(AG=r6}>+|8W^g+710 zfcz@yV{Ch|vlaof0mMaYf3~Z?2t{gNqtV~6at9r|%YQ*x+*}Wed*h}N=N)-P5N{M@ z!;#$dFK7`PnHo5Cje1x39P>8t6lgve(atj2)g}MjvDsWUS$^Z3ZATl#_P)s2HNSFX zqT+#`(W7xMC>HJr3d{a3cDPcw_fy&8-r%nQYUG+@Csi|;zECDg?*d&B?Fc&CoSZIT z`}jkOHD_5rk!UwePe|_4KR$I*xjw@?H1 zvZbk1it04WAxmMq>Yrm59XZ{}3=*}wQ51pOB#HCEU^(~e9pAxGK%v4azSn>95h3?* zvhK+@J{DVt2Fvuq-On)x^exI}vxhe>TurZrDM*M>8n(O&W6~?_+{muWH%cJxHkM$iGx(oPS zW0pEp8(VZ$J;nr>dNF~ z_pvH0npkQCd0z6fP6j#|b#`^&`;PW<)7+om@X`C>_<;V%+mu)iFRSFV&(zD1xb|U+ zluTkM(It9?|C-lJ5ci2DZOd9N{sCw38mW8sP0+ip58Xd?uK0LlU%7}2 zkl9uL)>5*Z;ZFDd2P9-@i+Q$H{eAW_M87BhNnLX{o7}6$KXygZv}=zv!rep^j5kkl zE9S<{C9FAhY!8NiKaPG*|AHFB8d(oZ=WFFsoQf3k51VVc+GgSQeWy{INuf$4f9kA( zF;!#t8Nvgl%*;;L^YC(tJ*@g9&`ZQG94bB0cpV5i2OpOet5A!U!2ek91z_v%pazBj z$zhbJ(kslsn{)|gJ&js`{qnOb3-x7c~&Jh6m$NoIza8$%@l&R@!GJau# zdO>NHRYjZwlC-v-iP2Fe-{U0)m+B)ii~vFJi9#1FQmG`=hZ#}|CH%O_tn0FoY9|ux zpU!YiAZ4g!uJ&D~LXP5(-IZ*=Dcu)=^HfOc)oRTpV~w9T!5R)MieK8k=9KW$JK4(R zcbTWK-+#!`v@MeGgVjtWMA1Xz;aT5l9l9nqvirUZtTsn??+p#|td>`Ap}sk}6sYM| zerZsFQ30k)to?=2ebTnVl3l~u*vM=m*iu+n*uK%L0J6)%Bpz&9+6&ZV0%p3j^8L#{ z01RmG&_Dj;Z^z3FFhEf&bX-1uPDS@P9Isw+R5ehA7hsbGg_dh00=%)8w~oJeA3XQ? zo$Nl}oc~)X0_FclPP>!nTJ)jt{P14BBMzQyztoK*=T?W}qk7OcZU#WakSj;v;J(T} z&C8~(6>`}mLa0*(UVJmmhNUJUsNTe&rC}nE++B#^Q@sK#EQcY^x_NnJ&ZQY2y*>be+n*9)Z ztNJTq5JqvaMSOBr{__ZnTEx}|q5j+?+)QIti#;4Ri}Va*+ka%C$G*VA1YLhqxJOzA z`Yq)gIXw%EDax-?PSM)3LpeT1jd2`eFB5>}ObJ(k*H@g052>u{DR_TDtW}J>W+6;N zH5i&_h0IO;;F*kj4w+IW#zZ2$tYM4EOVoF)LI#QqCIMvjVT(+2>YfxJ-h89}4Oq}{ zO{#lK-4vYdy#Jn@rQhZMqg(z1e0VS(J-k!_QUr&RE1N!eLKoZSbYHlYd5@dn+Sy!2 zsTy{NjZkt*kuT8=bh;{8p3=~t#*DdetcXv)oF<$*E`6!sft+E1W7M9C41w@-O*$b4b{}0-cw6!B#rM3Ss=UFk@7ID9u=K&{17dLh>q2W zr8_uff&E6}X&>AZm*m$00c=9o`difaVv0fF02Z%iOX~8jCo|;R6FG&h8~9dr{lI0~ zjbqmjdDoTjtr0$McdeUT2GLT8x%^K@;DaK3ithQ9?tY?p>)Ab=#DKGG>K}c`wO}NK4$}fP12Vlv;MAW!FOszsF z?4v{Ko$iNpc?A~Y3-ONq3EIYWXtnhCvrP|k+D$a9c3a#pf`sZMCd#^E95kg zFk@`!5Pt4zOJs`8A*2@=wn~<#@0D%a<>J1vFWN|8Z_Qd)Saa<`!*XD>x0ZCK7VTWp zr4PSEKbtjJ8;DwwuX5lr^(DNF9#6X;8~}C`Gc1geqx+TzYu?N`l}pa&%ARZZV%i{m z$nfe^)_FabH#N))xQmX=>sr&f3E9vrZNEX6KWc|sqN@`ckBJVROugUY>p?mjTaXnJ znQ(;98>w5x=G&9MohVXU^zSOQsg!&B4W&cFe5e$cH{EDs|MR;~ac99xKgZTGCeW%} zGE<_Bt+uwZ`EgP`(Vdo~uQE@XB)-SQVaa^1)Cv%F>XU_2wW5xHjL8CKyVyri4X|qR zB!Pz%J_>C2$nT{H8JzkkE;F~#$VTAFPe-$S{`-^PfG6cH;Z@fKYUvoja&0)emp`Lg zBj$=#aKq+BU+ftGy>*pzPT{{|6m8k>EKoWDU4KtL*qzXL%&)RzuV z)z98OhZ-nBDNs{OH8gz&`-Hz}Z`!IbKpADr9u=mn(E#?H7Y6iX*dFKawI0BDd8I60 zAz=>*95zy52vc$N4dgcD_urRw63HYgy>^2zLSmmxC|<{s!Y=x=@BFMQXZgUDwn#=C zDqOb3_eL2#Jv=mWUz$vWnB>xu)g!iOg*6AnEl<$T5bQDk$};=F!)eEw zeVR|C8{e@9$;nZBz3?asM0tYOe$San{?S8c6?$#VO9n|g5tWDryr#g=`G9CvmTsM! z*W*dA`IADL7Z=|)H2x^~Tu_KCp56r)9&A1TyHW9MyUAbK*>#5*aRS*S@Zx7*W2RI% z+j356p>f%HZymckdeM)VEM`T+InVXU<*~{pI8-7x(ZT3pbW>z-Vm_!z`)wfqj9s)N2 zXZ{d>N1Cxw!CHZy9id_NK#~C{d2ZQq&}-Q;)ha7Wlx>N&OSvjKd0pACw!nr4rK{-#IXq0Kffz{q0#6s+;?|-^27BxCPICd++CLt@QG?(-Y{K0ws-wW#67 zr&tHdO)({OO_8S25_7z(33{J51xZZGD@yEN;Bkh>q`48Tfr7qroBDK7JpQHG292T< z*RU8ZJSAV;@4js!Nb66q?{*_FaN0uW757zSXP+e@5HCjO(scAO_N8%)$pm*RWarK$ z#kz@L`|5HK#c_$pZ&2~uEl9F?J@BN3oO4mNL5<9to(t{OFyn6OOiO&mgj{>%I^H4{{0#8I;tU<9w(<@};L)DR2A>4#`!z>m#w^1FJ)i z7!DGh43Kn3HB(=C$GcUGEF(F++(C)zvfk=11=4+Es1;t|-eO#WN4pN?71C5bpnHTN z_u7%pMC??r6giKt%E!ac^)p4OQk%=|qK0{&Ch~7B+sP>rGgPYXn(^qqvV*yZ$jj;K zXv{YqZe)2}MN843IIM$JB`|!4P64hl*0ct33h`?=RoFy{X|sX)?9a`L*gWG58={{| zMZC+TD_{CS4UIw`!Yilj3nwh3QoF z6X1;U?KE)xZCcOAvWtEu?c*G^ZWPqLOAw{-70+QA(xLLP_MSnRBy^QnnGV+3+tjY) zy-qmk+_vz8l?m>+>!c`OZD~WPcKBVE>B?h2UDtk^#)$jS9K&so=SJzFdPJdw6-bPx zE+ZnKgmPFQ;`<)bbe3&Xk;W*-smsdlz7SU>I+lIxNv1g3L?FswLx5%mBRT%rjg;G6 zq$P#mb>MID1Firt53UKe;bNHwcjK$t9q#_KJ2}lcquFszg!cZ=kqhx}5H&{uhQEMH zL0W-xndJK2lufGEw^W}MlVy96FJ=`K1T3GjF}|KD=DaP^jkiL~nXn^YQeo#0Psre3 zb|dS=wHG)$ol(sWHybX#v193NliT0pOo*{Q4oC=rkbKpyE?#x_nP_v8a=t&)id!=d z+hFd zZ*|D{r(5O_(rO9C(QKeo=4XWw57<~nd3KGEV>N4WgpgPZ7INqBlTTD`6;Uf-1-Rz` zGZJdLvaHnVpACwJthUDJ8Q@FW{1c*4rwv6nSRGX0!cFL3Z)SE~PN@S++yeA-`z6`E zV*jO?llu-^SqhjEX)E+Gv<2(*%f||E0}uW^a<=LihOD2c0m~w+39_5^8}uL_hA2qI z$*n<7hN0>DJd5J_!8DmxOgvy8qvyDb%d~2_<&q;T5bbfVz-SS;I#J+&kIlh!6h{=u z$G<@@5A)B&i)sW00r@Huz)-|$rnYNWj zFV7(q>x$4aXu-`Dsa1^c?j=n-CVU3h48euffibO50d^mntnnLkOs;bYy!|B!%If&Y z9k+rr8r5{%8A)4W`VDG;igMtpf{QNF0->cCry{H^R_E9Kjo%=X^BEJngrFQaw6`UQ z@5jf7n81dKOkSGv5G)`|15OQoUWjM=0;F$Tk(Xit0|dzF1|R%@e8|=fFMc==0nSDa z$#pVZ8TQX_!V%&{z=Twx^Nv%3fslsdYYTAHdLKK@dege1*ZT?VU$X3~hr}oM5%^jHqT}J7Zna9DbY+l^JMs~aom#1d?32XP?qxSF z)yHVMB6sSXSmK@hcpVP{|vXyw2g(B-K(X=3l4D2<;HUikPij^GtDEe*BV2$Guj zF`wX4#hQ7b8}js=FTtxOZ>TCsM?Uw8_p5u$R^NC+P^?NQ!GUpZL_Omn_bRHgvwU%Q z3?Kit`@}pyi*rKNPH^hYBZ0nXtk}%2eCoU~n`BegJjg(kP;H0KC^hpLXIi`tV@COu zY!s(a?{zn1M)ja=!^`K};X@Pyoo{pUpEYtwn)_`gn4g`7#}PB2$)-btM~I(*IEn>z zc4DR9q6{83i1c$_lL`r#xUCmS*0-fV7k;|Iv%v;7pVXSekKYbIm_XWO>B-P7l)Jq% z%qX0S_qEK1xx4FK=p*Ov<%i+nZ|Hleo&y{Bk-E9?L0*oWoFba|&T(!QrYgC&yW5Ld zQvt9Yk@nV+kcFP`Fp{`8%n3O5JgJgLuRx*ObK9nhFA1*o!M3xKuoTW@ot$BMYCA;R zhLz)ivCB?1o^}2m^C6V4I&ikRL9YxQpF?788Hffs*!E4p#n}=GFZp65b{dyqdWMy? zmpQ$7nuz+(ceEoQR=7HKY&#yCXoy_huvCn_s9ifV3|IG%F#ZWe6)mnv`Gj$BYknuP z?m1SC^@PP3b*S;{V7f`Gs77dA&CagF7k_&q6@@tAxq1Lko|Eb-p3RISM2(-$IR)$Q zRD6R^H*qizP9?>4lV_Pd*0}NTnygeX+i4M6&Bwa>(qux_aE3A?v4d(RQx$mr;d{D` zodOAynYm4&_c8dq5-a90;GFE%-eeD=z375Si_Z0D#qOl?yhoLN zr@>iDQ`g;cqGup1FO4=iL({(Jbk@|E45@3=czPcmjmm(qu)2)h6>@JY0OlEQf8~&l zaBb}D!k^Ls_A0DzyaYZh2y-R$=;+0fiM?)`hlNRWvdF>!(^#2Z#^{uZ%1!*+xsHaM zlj|!V$mb0WoNk$T#>0hVMFYTQ8}EnYth)nZe2NN&2PlpDPJWbrQ+HvYK6I7lyHzyl zP#;v*<*`N?a0P=NJ5%pB-u39pBY%q_Q^)4XL{l3i?6-#Nw#FuoXH;JGsS?fyPLJ!? z<@3Bv9B)avGsXGlaM}7~*jb?>55&bGyZbR!G>e20uhD3-fiK~s%T^=x{60s> z&{DSzPkP;4w|KQ9)|spJ{j;?K*fM#jX8z9IkPN@CPa3AmY1Wg~S)}cQoEL7@i(JB! ze-8J(u}QYaQvj;vDyLZu-wwJ39GM>YIl%D9$)3D7c;0Q(f8DGZeCF*v!p> z_?A{2Tt$HeW-ARe9`2rm{oqQY!@CqlpZ>Y*L{Y*H9qQx~^u}^sHG#nvCB)s8lJ;FH z&=Im{$qUmlGx%DP-`k>u^UBvRV_-uDVO3y(8~9_J7Zb=K`;{?7t`*OKBdG*I43;0O z<7H4vUyl|s-%o%cxYM(o#n5>Wvzlc`9=-=>O*O7V9{2z&xeu&?E(ts$~rgxJ&V*6)~H&uuC=r#71vY+l1mQ1zc&8pVY6m(VP>Dv1u#HU0)U zg+kr}8B*15;&Zfp3*v*pnt$-AcbUw_{s>`Y_m9m{0boBgq7=IV%ZF#TrtmB1e|42>~VPCLg5#g5RKuq{U2-a`y-pLw(wMeHWADL1@QiW>_P|{J%lIazL4YzhF^|7l-1X1pXkc7qibv^2I0jA@i1m zKLWBQYNzkNQ_PLf8^a6X`}Ng{*2Y9MN7>6JH+|pnyOZu*{4Xlb@Pve8SoXpB6k@#( z#44u!l90`(M8EG*h+U|nR!dE^FTa!tJ@!fz z9|d2M`}DbPl4~vdr-vVc;F=f3MB;}3y`)|l&qj$0D+2IHO<@rWYcapdOYZtc&G!zO zx5$`66p9_JvlBgcb-S2v=_WP624I}aB9Ig<`Q!VEcw>&CT1rpT^}D2w^|QLDyY1`M zw*p82>hAC4+$Z`Dj@h(-4GkZWQXf!GEy!|N$m+%)mw%uxgcE9jDT#*m4*kK~`?^mog7BO%nvyRUrI(*q;^1Sc>ihpbpZ=-lePn3Q?k5lwe?c^tP6zMvU z|Ff^4Du8$g+>TN0j(LB)p$(83qjWGkwcXwm=c9TF$kDx6Nv-+Ea$= z_m|OZ_7sS1{rMGX@tkqV0xcD)nWo1IcdLkhW(8!mF`)^+{RYK7$Lr`S?AcOaTRoz? zduur8#i%2D&l+YtAr1=kulO$1tyd9?)hahX@S<3A>QS#x=lZUi>7~}nw>vhawyQ! zMUcz6iZj3@s!)mq91eu&5`*6$WHUf}LQfc_a#o>MW8-j6HrDV913}_nYoiwJ(^*1~ z08ZdBu+UiXT(wW9eiH|P?>Gk>fZ0G}kqc%vQLZpW=llweYpVF={OGEu96~%Q6bq+l zmP@u2LciTLCR_k(gh4(B7e=A)ReYuT4eFMw6Z66F0}ci>BE4uuJg+DNxga&Jefs@U}#)F%nq z%>x7!0X^v8*Y>No7lswTL2M_$$pCo#Y$QMg3*B1U2d|r-)CZSsBahmzUjE{M?B3pi zek^);+1`@|ofbm<28n6AqoJ|Bev-Fmnf?LW8GQd>Z!#I(H#oMxSbOYW%ss~YH0cuW zsyzy48>$pEi3Shp&4%odoiQEaY@?a>AFg1&(z5O7xZrBBWM=Vhv8kXnDkE3ubXHDj zR)nXC->1>1MDV<4HtJs5iZK+?qp|BPB zyj{x5#n3hT1nFjx>g|x+?*I9d4)8fsTKfjm9kS4Cj(YwqW7#2}&9~KM+5Es5(GsOD)S)}zQbuIca&B9-HT~|gLDvu;8wY?5S>N4<{s}6 za(+6=9vv?Tso^dT`MEILa_IoPu0?)t?I>|4w26Q@d@0&F5t#K?XG?(3T>C_E2ry=a zJ;b&61jhk}?^@K1cs$my^ON-Po6JCOa)IIN@T#g>KXIn+D_Gw`5ZV2)^cl~!PaAoA z7pSr_=EQuT9lqR$vQ#k3khFWD?IMuoAl3Uqix>z}%{u+&Rnazf^6~M!@PP1Yqg-uy z=8#jVn}`s-E4PhCyI2lb=&FD!=Dvj$}_jAWX?H zcRK!o)VI zCL7b9$UO46-nB4#n!%odJbQCe7VqqCQV+O_lHiy-p^)rhhgqvdru4@Bla>P4 z<$RGlyf;8HC$e~>lEY?#NDUE}A}-*w@KqmYu;ZoiN$!uf?@w4v&1Ej!8N9w;6kvnC z*45UND4L0p25p;$UKr}{+)9ZyDqoGESZ*-Sn#4Hgod-T?Wm~XhBdqfBJjaVp5xT+4 zkb;I)b3^oXj*;fu7165Mh?P8ybHfR$=wXz#V(_T5MSD9RE*#?`7vzTXP|dJ2m=&oF zw#%AsE^g&0EWG(KU-nD_|KwWv*K8*}O5*`B9Pa4_T>r?&uDYqrvndE1N!GsGw0U=E zEyY%SN4;O1-^{$vBW3bIfUBbS1qqtS6}gPxA0}}$X^V%65ViXVI?1mgcXXi644R-F zm3^;(TED7~!`ojI`X%lqMC?ovc0gd)cvl?&2j$~VXwe?j=jdLUU#&{#`l>fs6Ikj7 zRV775MF@Ndm!|9YPT8+3ljLRNgY;c0Ke$b=k*c!c!K_s)R$zToYKt4n*QRd(G6|DM z-VtC?-_9WMXaW04O`;3o>Kxj;|$C2!7 z0wQQPEk%Sj)6Q3IiGZ6X!yN3~j*^`~KXN0ab+pZwedG>?9>X75P^iRyOVxA@UxEj8 zWu!zy$Sz8$gKnD-l(8|C9)@vm0;A(lkBjv^ZX$YCVuV@9)NiWFJdK*i zBVd&uEozgY>`wT$JlWC~`d}^5j5_>D3iJpEm~Cf}&w#|=J|IZxW^om`yJ*MC9SulJ zNWCnq>&z7}{gpihu%@QL;g?fjW5M`3^9=pPVT1ojEyCyKO(7%1*o zSVeP;E`rVeA%P|708q*&rV%LG+I|F-6-Im$lujK$i~rKU5P<##nBl+l z@8o~!U)4YK?`0bV6Wse3iGF9W31;{WdXMQDSIBJ;|1(iUW&VGW=fCtXpltqM`uC-b z4j~H4PlI*A@;3beqkj*AAjq35(j0#X;9Fpv!ZyGeg8@KKcN?I9p)+Eb5)(j|41mr6 z+|`&dP^O&v-u;Z?xIEw~#MsyPd}+z&h>Wim}iF zUq6YNSq1=+KAgyUoQji8-`2_2`GJ4Ngq_3`(}J6q_OsUIbKDHJ?pzfC@H4gU@7I(! zpe4_CiVa>`FxvGTDxyq8yaxc#0`n5Ttlf5eEdQL;9g9s65S3HTf3`V>_NdX#8Rp5! zx=(#K=Ftnoj4(V7I%B=b3`&K~*=7|GtCU~af-#%j6VE;gh!PHJ=Hsc=uaGxV5eBRF zkJfKD5Ee1M+e+=_Y4Z9k0nd@suFyF;CX@fuN$OFAsZIKzOseuc#d;s6w8V{MIO7{L zXO$6S+(u=Xq&Xdrfhw zhO^5WiM6b9EVa6eypcETt?%N+ls&BONc>CK(^TKT9<=m1+JU3o@CWjnf5l_bSYWR6 zJd(d)bkJ@znIE;8ujP`iI~;$*d)qMh%c2v#+&8)$Y(wGWRoCv@83 zg--YOIym`RR~OZm8j=@=pSGBjl>T{rD+B}rZPv*)2jA}li1+CDumI8-nu$kWcitDj zbg~b)1~D6S9*Z=(g`{Do=_72@OHh-L0D=|y5Yp)`&z>z}$I+!}j(SG>xsEzXh)r4N zo(#px>q+3pGY+Z&e)3t~uYhhgSb?pT4>DIF#(FcZr|KZjmYjBm{Ie)n=pYsx#aH#KAr{()h$6?0DrV%iW(xH5E(5{x~14C>p3=7 zFV=!;AhlJaXI%yb@khl|8#RZ=OkMe1Tc}jvsFXP=*}FE-)JZNy3HkIatwmqh>EQvT zsDSURYE$udO6Kc&Cz7~ihZi3jB<&8ql3JpUt5)aWW?u$fM>51|>&&V%rk{>cQY`c5 zydPu}&7hfw9U-3xwRV#UW>;s{0yH`zapykl=$Ur5YRg8xK{po&p{N#a+YzNrrYL zZg$CVvLN)0SD0v1C*E5nT#!q`#9oeSDrGKE%+AYNSK)-5?G$#1J=CVB>VZfhXy4r{ zc*SY$3f%rhoYRJR{N5fCB{u8IUxLJWj@bc!lsb?(8!Z#nzL^MJV$aWQE+5HsddYE| zr>>1M8VK_MjdFjg3nEjuWJj`pj8UX_UI2k$#y#M zwl!sk9-NKU_Xsj(gmmD?gZ6q2)D4B&*LZ{`AnQ*I!_xJh`R-`b9^7`-EAr$tNV#rq zb9$)SAS=850vN|~dstHmjSss4VuoW%s;-WqGggPCV_6GYxFcNhr{}Z8+^#A~E{2<# z6;`O6|BWh3QkHi1aN!q5E$-;mBb-s4PUz(gnjf$dv7f%Q>8~Ps2JoURa$mXqp=l7896()|@tJ3w zeP(tE7mziQy5|KQ1z40IqgPgs>p?&yv|ar&G1lq&28`GC$9H*x#HtVwK0HL)x74q0 zUb}G;n2h=PM-*8!t)tzJ1&D!A$)G&Dg7Sb&M#Plof>o5z#qE zi5&Ek$$mt?W_cF-%p4bRS%FaEAV#_GLYPzctF3A2^H;hVnjY;3*1%dGvZVz}+4~#; zy+mu!elN*Wz*clDUA<`k^}YQdPj!xKTCP4>{G26j&f8St60Gsu?D9Kj#19(^Ud-;rHw0j2)2606%QpO^;wWBqk zZ#~q_`V|p8CrnQxjE~JTFXWcjB&26vqcW7))}+}05|y8yQr(jvYWuhlR1f{<-z~WE zS;akV$DX)EP!IMVfN_`iSMD}}TcKB5<7j`_mH10(SOY*h$S&b7#i>%%RW^Wjq<+bL zml&r4&<|DcA&0@7mT2-EN0^7skW-n|Qz{vfunpBGED`8&cD_AB)^N|!;{ryy6VBQi z#qay{@XP3t`c^ppkaQanJ$s$hnPVx==*FT-}31OdQ%5M1?o+i}<9@=^%9+t=RIGxswGG3=0GpN+^I38KZ;%=U zJp>g~2lX6$sFL9M6JbK3(+IQy&kng3(ftVq`!mIDjHWpTqRIi&;@?=#fVcCo9cZ#0 z>!ZxR$E3}FJg-A`VO4HReMb?L0@&qx=j#+)viHRzPKU42Vz#eO^Epct8 zbR{q%BrX%>OT3&O68oqnXb7ngticMNf7hO1|lc&!1({ohy zG}lap-b9Rb-M*50K=Z2`kAyNs@i>Ex+ybux8+&Z-60%9fP>di-L%W?t1FF`tdK*?$ z6Yjo=Z^J4-)D~Pc6JyXfs7_T#lnf@s2d1ZpK=dpK4N>q1yQ5*=ZL@7xGTTHA5l*0g zV-V=yI6{g{*Su(7#Q?e92*Hn;Jm*PR%?W@?0L%dl{{er>)rhzP%vH{EvY^7L02K zuko{PtwRq4##8p8Go5Jgz#Blc1eOBLEc9V8cpw=v-7pE{TWbS+CQAS=0?OR??RiQ3E8?0d?%FHNdOmWDv@53?FBpn zp-6?#t3iL<0!uq{0FeBkdy#WiFB02Ce~EprfNFRlB8guQ{bVqesrQn+L(OPjE|1=0g!8619GEOv?(!@WP{AjdS-2pc@;>#)4oU9 za?<}4V7#U-S)M6M%3FqqC(ppJ_tb8AlNMgZAjd8d*q>W#41fGJ`;DYtm_GsjTvpMx z($jg~J3l`heWy4njl$_k3pWAsrr^&KxubH4KxZee5~(Bl#aB&SIsKMT`{AEtJ#iDp zPpT}g+G|#9=51U0h1B&~lqfu(+)k|@Q0K)vrQ6o4(A)aq@5^tTQ9+b(qT|H;0XGyy zHA5nSBxs5?eC4Uia6*CyF3?LfknKD+0?7_~V@jUa4u02GAYj~a=Cf3FqoD8|HJaOy z(#+^@ic>#Gt0B#aV&TtE6CZn#0)9L(r*L1?HEE6fjqW_-nCUEPDu>Y9?V&D+^U7dt z)$ zC^^?$`%aOzvu1AvKWaHP$Dn&;l}%wL{^^^9arq?ld~!HcETa^qA^xr*%5uvy8vZ~~ zT=Qu>z66j(Ulhs1phyIX^~$o>SMQ-HmJkn^c=={;kW$tqvyes5x_7^gsz4CIwoH=m zN(7e)lMXkzzJEI-?fstfXflIr55M&emz`9JXWcvGnt$a@YS|t20#b53!fh>b76pEg z+_&rud+Q(<>3c5Uri1sSHND=PZkQ(%2yZ!4JlI(R<#4o1Ag#%X3DR8P4LqDLZ`8$V z$C|Iiy|^I-$}-fNI` zy`y7vUH9WBu8R)|7Mk1B<=qH2KxomTUX+Iho?qj)i!MUxcPk1kp2y5Ru}!Enb!4rL z&kg6MlfS2f&rrNM!AMLTZ43mk3f4b1b<1APvI-clMZcF^=bnWJroQ+Qt>WurOyI-D z*fSYI^Oz8y<05UYiXl1DvlmVG-Wt@@h@UNi)$&$7A1X6&yB}o#Tu=F0v%Cthvi?cr znwWTaIr%5$GPRBOCyS~6pQA0DVN(vED4nSu7ogm&fzG}+Z=mPra2!6c|Bp5UHmtCB zkY&gvQ2_$>6@16%X*_7xLglWXws zs`t`J=m#7J5O@*hFsva!*Kg}RU6J;H(wsmMDsxzib|43&$pzQ?$J*+*w37|kx}Dc6 zFt3IFkdn>q_+npP>!BZ!Y|8kSG{DuOjYNr=vot;u>1t8}a8%8NK$w6PEtX-!Me`yH z&u6!BvB#odG3&+Vp6*9(nFDM3VATRkDQx_OVkHRbVQnJj5tDjc>TBF_#)63RO#68% zoSfy2SV`6#$wTehrmLe=dg^OFWai|OEQNx=(;175HA(P7=i31<7UI>O5TC4tK_DZI zx!r#<;Ju`c7n95T;wl$J>^br7?8tr2ttySIZe{2`&{`0gIb#(ZVyN zJ7ny^?RmbXR|6x&nQ-Bz=oiP;`K7cba`)%^R7(7w$yGz zihtZn6a)qCGdLa0k13JT&0^159{j+sy{vFXUwB`y@gmRoGQ@@d%;ZQL0B?5$c-LZ> zUq#>idpPuQhGBR2tas`DK2@86IBElmd|f zN>pJKJN#=k-E@BT8QwkogpKOASq)#|4hg_RhI|j|Y2aSt&rPF+9ujiGzxfo`2?(*} z17=&{peVqb0_7LH*G(OR83>32I=`NpQ1u2DRp*e>JLu%FK)y8X7$)F5es*(H< z!thn#zfM*)XjFji($Udx5C}ZdB9*bbtoR!=_>XaQ;Wr4tq0X8A4cglY(y|l!@n|>y zH^>tR8@g*EauE0=>BF~cs*eLGgA|HQkaweq$l_Fwkq&f%3~!jK*h2akY1oYMi)Dj) z>m1eHi%m7myZ7j2;)(TTgG#k;HnA}&5U}=?X$JXn+IP9P;w35&f+M{z4K4E>)?B3$ zPn|P3D!gKJu_bhkHR*#q2dZ}lHs@quBW22-{P+45H=B$Jf_?e~dva)Gyyy!@ScneJ zeM(Y|4b0RcJ%)5#WS`xAfT!z0sSDjWTdtkNf1)kQw3Vbc>i}&EFeb+v$z~ucw7Si+& z%h_u68vFd6Z!m8nl=2caJb75GqlZRh?c-=OwFbGYmJ zPD?vkyBbiuPZVb#E@|8UBGrJuqiq18sHOKC^da;&$R7wa`!AqB`{-oq5b zurB|9bmu>gS4|#_KM&RiiX|`v{I0J5^}Ck*>vt9V>v#2rmi&MGuCf31yQT|a0<#LF zK4f(h?l)W&T`*q%_p5?B-8VpPybVa~JkBOKp<7`|?Uu89tKb>Vqk{ zj<55E!_zcQn+CT7-p|iVy$Jd+^3#K&z0d_2y*gU$U(j!zPcC)z)u#2dQqfi=P8>gi zfCNSXe7|A z9g*rs&S&VBu6>7bJi1!KhT!y9{i5eY!~H#@FA>3c;U?`h_=zfFN>0Xo5g(RU>s+Ny zHjo@2f7nhn+|n%c?E{#>8l2Zv2;?2YKGqhba={vzyV!A@4YPa1o>IISEBC4}L8?li zk6<#KeDzoHqs0syGpblA^F!fO9M00Br|JcBa58m@40Ck#I7sqEU}jQ>kqQuk6v1W3 zFzo$=UGPl;?*5tiy;mD>|53681A0t1bLjclLIam(ieO)usKSUS-_?u^Y&u!+6FsIQ ze2zU)E!ji8^YrU&t@jkHLF$jf-5)&A^{&nr?w89!Yl;HS5z2_tjr)*GW5i~i!FHn@+2Ngpuyr%M19#gy4r=FT+|?*dR}3(i%5z5n9~|pw zoL2XvPUt4Ro>l=O)jQ8wdz1RrM|2NAZ|$(ke54y_qkb3_?Nu%+O=Gkpkm^;9v$G%Y)m^B8TmnxUA&4)kyIFT=h{e~i~&kQf*3kU z8LClGu(--x@0kfzNWI9NUP)Uo=wriQQ>mR~vf7W0r0Pl#deQ5eO*QuULjl;yxp`y3 zR7{XL>=gD(oYRW3VkLf~XCacP<1WQ7aq>@mnNEcqHy(@NXLG`%qn#`2U+?rjV5hTV zw48V_g;R+I!dZNiIG{*?uB6y-a$>^1#DJh;ni|rCx+B1mCt!Jp@|&srF!%#no5R0Z z*6JzivH@T<^)Fbx&H=6X4{rVNn(fS*KjHxMrr=T)Q*vH%yZx9tbsKz)NbQcPf_%BC zKs90X|KTnZ0Apf0b`{H?b)*jHHqbBSs<;yOGuTPl?rYwkofw^QTmh3iS{JZ#{x7|} zY8=VXGVJUfa$6=?TvT;SK+8w-4ZXCe?C81vr+dp3 z%b3w~6PF6|mpv^Gof0rF1z-3|g3ScV7cD|_o$D8hTnw~bUcTJU#ISBPV|!6eV8Yvz3>OiwrH&q@Gs z_Mf?`O?|h!ZT>yLxG=PL{7(*ql#^NCh&pFT*2zDGMJ)h6$TBblb_DAGXzuM-30SR1 zIEnOeXj8GFWu1`oy8zSQHbr%rWCotg zDW*YzC~lR+huWg#61%(VD(M0HMj9SKYsML)w5`u`2i@_;*$y=8n*b`k+1~pac0kBB zrvQFG%eym#&7Iu&?OtHG1x;I`WFJ2E<9$mD)va~T+}cN_(=|U;FM$;*)Hr1K$tmOr z17*~FX5~kpoUrjwe-0z&=_4}C}fEvAD&Acet1MzG7wSeH*ab7*l zI6nU_ag|%D46vhRuok1-tIb_)S!rrRx3K0C+!5WCgQI zrFLJt;}$S|qnBSVvo@TDaTP~}|CQKHRxK>z#7`qNftMXV0Y)!?*YUeFK)l1q2d@I; zX!5o2Gb=z_k5$ndD*2*MdyNDn99+bJDbWj32e+dDC0*d`61Ks|8ztNMAHvl0bKXU? ztX%C_CICCn&)s`3ChP9TK3EG)LiEriTygq!PNH+>AHOUt95qf#QV=?T<3cct1bQQP-gr`R4^1%&@3 zzK1WNPe?19r`RfNgDzPw3L>*%)P0|-UnBN*`A8qXg`tnNC+W^^BA+~dn@hH0E)c;J zVTj2FHb|;Gg@h|cZ+XIv$B7g|M+EpxH+?17{iKIF?x28@=7_v^qkX1eC4Glpqt)3@ zRm`tDV7+uVwY1v4^&I#ainuZh6E5b#he_nUf|K*Bdg=S{-Zl-ZB|g%gh?Yyj=KWNx zPTVk2eK0Y^OtzV2XTX~g6Unpt)ayh1X20>-SNWL+1_8G*KHP3O#H_-3wpmrbdtl`L zkHmfbcTeIt>1E?yAs)Fhho;h><-_;fzGw8rqO3ij%p?isd-ySDy^!LfVQ)r}nDe1&Q@k%6Z6zI8#D*XEhsPw$mUPk(s}VAfC3;S!O|L~L51}8n&IrWiZ5ypA zKJ_CHDhc$l&8Euax1$_UD>vdIw39lIdXPl&h$Y|1cFn;I(rw(LN;NthzU3mdocoXs zE01&<)>P6od-%LuUM4i!-^;*>Iqo9g*mzq*p1}S`UGOt)GtuiYgWNZP7nQD{&={~c zes&N#{KSDTQlrHcAq?CfZqAN;NNWpbr8nl*F(SDZ{gk?86t>DTrk3AAo7BI$_P>h1 zwgz^7JDQXMPuSMuuM@25kL{h&tsd)3Gmwf%6YkWOw;7u%eQtA%XPV?FV;wLl#7!n~ zaRUTejn2GAO5z#f-FZ2Mc*ykAdxd|*tM#Mp^dgPK4NghIlIW3IkmUkM7@rb!nKo5B zItyay#2I~bBSHz`NwO|O!L3-VZ;C6L&U%M5LhoPAlan}fa~bbPXwgqSQ>TST|!WKuDHK&a2D{X0RG88 zO7}lp=0d~e5iq1*UeqyEnME6<_tok0R$lQ+Zb+FU&P@HdTvp{3Bt(2>3rAKHrkr@J z(ircfa9k{h9o>*iZqrub?U)(06+t_5r$il9W$49r2UfmLI0lUBii`Bwu))atv4qO< zAaF>bRpA!u(o?@jp_8S@$?dj}e>uPY>;9Th4I{SsPjfpX&o-7g?~-!;#~5+Va@x!0fPF?uBB=dnEHXOD1Q*je*l#!D+?f@?F#oK&bLnDu_Q5gzLr zH}698vbWXoFB5~fn3%)2Ph@vNPA2?aZ`i0385`8s7^RJq=EACl%TVjVkuU1SG%0oa z$ZvS*oE!RGil}g_S5r8EQ2-O{lJB;;t{)th|6q^t;Nt`*%lD8X{`!gaE-HS#wQznV zS6abjg)D=9#IK7fmsmU1+L5c2PoX^=3=EeiWlb1cS}F(oXzBZJd5-DcBfiZ_yfD7= zi?`jRXv2q(6n3VY<^7d&QMs6VXNOlc$0lo_u^)}qKS_2;1)Zqa z>62$>ljiU9GOj3jL>UwJY0-cyziJsUN;yvZiTZu{970q~#Ts{Rm#WuvHhB2s{WF%F(6Nf!RThM1@&UZ-~MmS0cA|&4;mIk z>9~TsfC|{@W_oK&b`1Kxl+0x?aPMX(!sA8y;=goop=bTy$bbfDa5So_y{(Qu1s(4MSvLn62K*YV)Sb7EMw6y7Qo{o zUaO~jj76Wz;weBDFC6sV*(<{RLo&kvsp2(4TuKL4-aZd^eweN9Y@vd2Y7Cejt)2IDWY(eVD+ZQgc@E zToYG-ZDgXQ^V5H4>czo#jnT-1>qS`6Ki|_>FP^zTf`8^>Qam|zEa#3&CqxM%e=mD8 z)e#Nr-(`zMi(NTS(Q^R_9&(=D(fltEhzZvt{z&4bza{ZVwEmwM&*N~x|I)|THyz6= zg&$+IaHtk5_({x8V@sM_oYk<32QrVR|RQ1wf%6s$?N36a3jf^c9#5NnYDt633CF7FU`bmkTjCsB zIp{-7!unzjL+C>Iq)$I{M~Rcl?Fgydw4vJJ(2SvIqX_q@v^TkDR(K1hn9kX>+UJY`U=JJ`9Ag}MV zL7#rNF&Ft%ZtEc6Nk4k+s2!`1bFG$Rqs>iqNPZ`4YSR9`0*j&n%Z`Sk4~grkHJs7E zSB4SGtYIj;$L*_vD-#KJ3zoLiWl={3<^n?N@A9Wuhr5_Jiwh4VsLU!ej3Axdqd%P zNP2P-J9uEsT3DCsVzRr|bD-j!d)>v3`^ln(m2_o}ak@0Go3vno! zEROk6`5o1LwwSYAd|@myNf{m~>7~K~aYrA{Zq28-#3=`OZVbWd1nuQRXNq85)&y!UBF%=><(5>8`o zr?%JpGfxdE2p3gs2IO0vA2=I4B$%HhtWv?x@yCAynv%8rNA^tovxAggO(%aaT44>c z)=~K}7iGhk%{|9Y<#f#qmt`Rq@BoWN25GjuArrUh$RjxKhslz1xw$&_3(U$`*EP-*q#5x?90*En;_QNo@+h*U8SMhb+! ztR%JwC>`zYckXTX8Xo!dswK5c3%Mw=yHMH^$?DCoeTS1J>X}H%1+1T1*ZKAHN=%d? zZ8ixd&ier!O+Sk}Jx0n9;67nqS<D?8rB+?JCuexBZ!V9RAdX3&EzwsrZ)C7S72@F zK<8noz{1CvYhXdEgB-tVnt=^vm3?rVmtY5yiDr1sae;*Y5p9hPx)vj2Cp4{>0Fxta zjqSOtU4;66n}@v(qOCsk{E5ADHQo1eMGp$H+82%Kkqis}~uhS$Y8f;|7j5`yxGPC>Be;{&+Ya8~RF}8e z-ExqeLfr0HdoZ4yx;30Gv961UgKdKJCZznTkyb2F{80C#J*#o2Hf=|xa$(`Z2Hx|Z^kk(XLhYt#aTuSBesyJS-P3z`Z*VRgT~1#Tmyr`aQQnGB z3CgQ0>}pDl&UIaQuj!=0^57cuqm3WzO0Q{;vrx}=vTjtGf*bqMSo$e5?Q~DjOO+Hm ztkaFRgtKm3yA0UltjwNL7hpR>>W=9LQpIK=`Gmz0Nn<_bJ#thBh!+0M;&k;m=>R@S z*3M3KDEpDFo>jJ0LdeCBF_#7UIi}N}GZ22&eOihCeJ|vWM}nM)MI@`#rhwz|URUOx zr7=`Kj_p~W2vv@05uc^?^E|6$_{XuOY;GyHbvw(0dTsK+AOp*;%_N%BBF&#e+=tkB zxA_#y#lW1f?iJxzmv%MP^17o{3BKO@P`(XalYQ+~^qD>>q#3WkwtHqum&%X?I2q%% zSO=55HLUu1&88DggJw=XMcnb=djiGdClqgiXy~mi&`mR|3*T|NWrU5RdJlKNfA+gX z6|EkN zq5KY)Q0__P*IBMKgxO>ot5Rz!k1Au@=?OZxhu8E4bF=yLrbDmd#|iR0aBRT>>2w=m z+dG;SNj=2Zkn~`Tk72RIvelV|`KvMZI@vuP+J&DkO!(oEjwz64_fxK$niTJMMcH-i zlJoIxTshk)b)$&p5pR`Aud7Y7Pay(T=(jF^{>ki>35BH#MoqG1MMU&o>P`_|6p_e* z8@v}bP#{lwR^jtvTW)1d1zKbNX@#Sme#hMB(|Z^((v@+AanzBc;tSK&p9)yPA`@z= z-ehX_?Im3-PMweVYaH?akIZMZUpFx8W~K?0x841iC-936}2$X^Xt_!=^C`3_4##snX1D3 zNS5zFdCExcEA2Vn{NH3I6L;jE%5H(+?BNdLcoh+a+J=qZ8Oj)LS{wqsPKc-iuk3`! zAPsNU01TdF`C!3huVfcpnFz|Fc01A9;CU-?+&Z&70g3guHaR&yK0h#-V z#f8bU*3&{g*kTJ}BO9^G1iVxKPe2HGJY@bamH8M$Wy<`bGPfcXJ=TUPzaSQ;k{!+i zLIxNTll^cg9TO2+vJ&Soi2v+-PF>#BY(o6i&4brrsldThS#m(P4q)&0Ig9xku$YJr zFhg8*Ibls?i4pGwTP1jg7U!EFE86xrJ$LWiOCfXMj&Y1lua`BR{J^C?qY1(9{jk>F zt6pLGN*g;ih7^{nWFByjqMR`h%kS<&JfF@Wg?S6(9Ep3ID8UqET8`;xL6^c>=D2F0 zsC8;1w>3P(_!$9zFs!fCCi@JZdI_6x$@`K)Lf#S2EdB>5+?ex{ht88~Vvs!(tviX_5>t!vvOFJ`<)aK6HLq;+^}a zo?~z0q4$#QTK6wWb*)B(%7^zSN#Yjl6An|K6*W#@0t|>dg^&e>yB+IPmytU3s*?Ixh4@D7v_q`;f{3+`sMr3?YCBKVC!o-7EnnGiC-sgrseC_MwjZk>dR_2g zVTsS}0n>#_ZI0oRUKPE{hsxsA(pLh%AqMIsv#W6G!}09*n!aP7_FiAL-b5b z)=R%JHf8Xc)wvumn)yEPk7x9^46hGvYmeDa2|@mmvg+1nfVR^?*zATL8iTM0ice;b zh}Cu@kF=E*WvSEWpZ|mPsR6^Zs(t^{Tb z;g|x{Uo}gQ_jJJ5It@QBUTV5`TDbn4q=)E-+~`%In`8zyAHEtMxs%8L%*BOvuF5$e z)K=PBEL`W`+v*&T>1Yx!v$8b zQ${JVhyFn7HC@yw6b6$Vd49OteE4lETHM7l6aMzgNHuLQl0nu<+)i>Bm2H07YJJdL< za0f{q!n2>S4{sC5s8}s-$K)D%tA%Bs^wtW#m-tM^)IK5RE*}ROfVZ?cLniMab_OtC zl@n22`VZFc&!QvH!~OnChnUc_Q?(zW2u1vVeIN&V;vM?%{EKOe6*jrZjT9b;>XDm< zM~?{HYQZxl-!0XJe~(HRc%W2KpEMOiHn0bYKoBRMSbs;_6QXgzv(|tHRQD`Xy~Af^ zo$E6s^&ZwE6P6zWZwjLB3&=4kbsFM;>T9xj-KRz))Be2gKC>6$V4tdT%bl2iJL$p1 z?9{f3%D&w^`^h~JS5)-^?&c0p)sICU!3V58FKuV%$AvG3Is3R*w9s_n`FP_yx3(tg zeBZ1~X4H<3V{J;J8oXq;33=Ca&{^nY*b8NSEy5CoMI$04$iPKWxn*o3c0XCODy-aq zw;rolVOvGHIK!`%(XH>cBF`R?tZ`MRI8ii+Tcm$UPWBs?l-zfPWe5$e5bP!7o7Gjt z`57b_$u~3j`)aq1_^AYHM9d=#px2$#MlD-7=3@z)n6j_N1o1JOqzMpMk26VK7!Ip2 z*)pN#vM%oY^mSB1s}r|MBsvOby_=|Ao+;j3qeaYHR68f3LgYu)H)|V>a-2J+CccV@ zMer+A3oB9TQ`N=A@{jfdQ!5xkO%5~4e0O@PSEhhF1hM#4BKsJ=F@I8doScoEk~>Gf zzecAJ??Q*wl*Of!^0nmjqou@-b!tS`x;Unzk3?API_4!qItGv3+C&vJZt3~t`CIVe zC6easUdKLlPUhPxZLiSud>>2~DIm2I6fKM0_kc`!ucL~4{YGbK&clvKXN@Gi5g8nM z246Y-Os{-HDK5eC+C@hH=%a`|es#Nkr}g0gE9d@gL50XC3euHMmx{?85GD64NXl=7 z$&ye;1&c*bO6-Y|==1gkO07~G#cpg#mp@N`?rqu7AfVE%6mJ=t@WwXs*zq`d3^Me_ z79^O?RG^^m=+7KOq4R%=mTF%df%p=f?LV4)edc15mNamEQcg;p9EqBM(52FW7ASZV z7)MJ`FEZN$aC1nLf7%#IpLAjnC3SQye-y~@R%RU&vxJen|EKH}K-YhlonkQTi-ScB zIh%>T@!u9uFU0?KfIj|T4p3NMnHu<)1km!YAP-nuz?YmCpQ8P2L|@w| zcXTO1g3UfZ|2@QXGx7%-k!h@U_~Y@x4~NG6>b7gU~EOL=}?;G zF%*tos`t4}vb&|nJISZMTy$}>?C4c;N~2-LhmSb2j%jsJNOyGxb;nReS)5W);Ubhv zKn|E8^e2#ey{x)v623ttTaH&0EK`x`mBsq+qM^jaA91&zQN8;xz5Ci{5S7H)O5TUn ziH3I^20Zi3n{%MSbv%q*)8D`2G&RAD9kt;n^=)8KleqAaEM=jh(7NXP8nz0?k2x;= zdnL5pLxw$;5!xsoDZ*+ZDwOYrs)Y`zaIU$7w|3LX_p)b{M7-VLNIBlhOjWu-cu%IME!!UVv|iz9v!iy1`h{k;dc6#}m;NI>NSmlThOOF_h<&<6vnbA0)DlR|&Rmd{#;NjPsddEZb#F9q@Tz^VXS+-DE(yZhHf}oGXRpyIvs`UgkoOPC=Mk3 z`p7$6pElHNLJry?6i_!(hD)evN6PW(G8U*Ha$}~l=B^3B=S+9JU;4>|(Y&Yu3b}PE zW1an}go$H5*Gu4IqTQ4UnAX%wtY~MR@nIz7x!v6FxTco8DO<$$I)^7Hec=FVAwE(C|ZygtWd}GE}N(66?)MG=JMdjr+>Tcwj zbNYsI{av#ULY~mGNz1ljS8mk+w5*QyK?fK|elDB+8Nu~Xr<-NcAxV7&&xM9r z1QMM|aG6Y!D_e-wIW3$<1I3|~$wPQ0^B*irglK;Me$_JK9oH25l^f>|6k#5aC7mC8 zTk|b3a~zJ|hAo^Ct!DWefEkVkG!~#>K%D&-!UUlt>FD2CB=F#`jQc&Wi!zj?qkzsm zeGc?@Y|NRNml@pVJ~n-aoZ)F6pn{qYo?xO#oOeKeU3VRrJ_Fe>rcc%%**tRJ8*TRZ z{=uS5-y1*WT6*4ko=JjXGD(R4M3Qt(YKVTo_5r92!DOab? ze9P$@t9P|KQe|XUQvDtz@8@1Kt&gR%5yB$kdvL(o+&>=%FAtKr!501C`$cH8#3>wF z8T|gS!130o+WnBZ$d5mcAtm|`>Es{G2pa^EwJMMp)NH>{@&y z-;`l_baP;(@5C!9gdVi{>=ij~NI=rDUCDUThBzU^lwLM=$R@Ar^M{oGU=3q0NpRko z#_dm%$Qb+J9rpYgZTQ=jj2Z0Hx0Z?0`GhpEdD+W3*TyL^RB}a|h+{qK?XN&?{R` z^YyBJInO{zc`Z7x9Ca$6$`AV23pB2;nI_3y#xgoM5RB)El8x$cj9UMs5f@o6 z--(tjRpI?)S>Uvzl*wC?8vc>JPe3fkN$Lag7}T_&`m;IGxw)xFjBrFw0anp3o|t;A zaHjyz1P`L#-MfTV}0K*Cbdbkw?49^vzN=147lCz*!M{x7mRnyV~G(>^tQI2IP6ltM*p zDbapD@vxGm4IOKDDB*5#(XTZw{p@2Mc-bi;9fgY2w7Cn@`v zApTD&XLcdO9bn=-cVkwkZ!Cf51ei1DZVqVK!p6JM-}Z9Q1mG-uGfU<_8FnV`MSz0- zm1sBo-Fff+z3>N+rJ1KjeGg=GUVe++wtT2m^iDx-=G0ne?NA$rQSE=ih}AN4#a}&o ze7FxBrN8v~^Y+cM^Y+b=rt|hq$a(u_4+t)KjIK2;?!yiYj%Yy%CO;MIp<$>F1O8R-|M~4qKQZrPv*7Rcq1b2WtQ+%-N z=0U-+z}Noc6GZEg2ILP49PkEF(a1CBy)_J>Y5IrIjEOw9oISo!5PACiT$l$>z%%ff z?EiNJ=uhSS-w4oo<-O5y`pUn`H$n2JW(a)iXz|H4RZ1dY%RJAl=j`UfTz?hbPvvog z1keaVQA+U)jnU|po-~F066rC>kK4N)W6&hi*vktzU=g|K;OzgknrvR>4b25Lc6zk- z&Ve0l<28cIHbFsB1PVkzS*x!4MP?+*}~5E7hFSMn=8>r5QvVRu#`?h*PbM|D^{iss~w+SQlbt} z4^YP#}IA>-OB4rat(lp+-Yg3nd|S5XtYlAq{WTyo((cm{Q9~dda0teDK4h zXJ@HWgoE09j<|zP!M(L0YNl6AxU-&ynS*|G(18D)I94e1ESwDGAbcJ!`gJDEoh0ci20p+UF%n<&H9Nmcnbw7Oi){S$uHy{GCC@FA7qHf!nZlo(CL^C>WUdPYX&L|3I1 zM19cf(3i+<$5AIy&25;W(eA+YM*c^X6z-3biwz;f^gd)JdO@a6+D4Ek`uCDG-pVD0 zXr^qLsM4+Q`>0-$6D#guL5mdL*iUWn+3&rgOZ&31rt!*vorZD0G*Bh!?2+4YEKk?%8{JWIRXonc@91&izEij4uCEha z{&*6%qmz*qRGv#+YNE~2cUyjLkuVn?b!fJR+WQu*SV@^D;>U2B8^^pu-b zqua1xp-nsH6BS2e(EBgiF|5QFCWu-#(2fd1BWh2Xul`8rC+Q}IiDt5{D{*t(GWOwY z=@$ogc{YH~n-^EBH0<4ZfI;hPtZM@WwJQy=vrbdZshFf?lyZ)%Jb&aT;_fsPt$A(M^=DKo z@P$GJsVYQgS7hiFAROo-jxNqPP9x%N%R+Xsn#Jytp#m<$c*X?BZ#~@5jh(z@X^7IK zL?W>VeB_wwIgGjBWmdzE!zjMWrEDUp689tiT_Eq5$**1pE}{P?`;!CPP&>&!(i{LT zDa_mTJLMYZ^8UZ@;3e>rQ-ItguzAXPCOsu{yZ#>-c&7dy_&jrFF+R`xje=$&=xe<% za%cY=0&0V~Kec0^Z9BpCv=HwQxiSwUHrYR(LDn^DPNL9|&e5XBd#$U8czDg%ClZTC z@FGxQ1TG({1-^Rng5x;;i3r|4WuB1Rr9t0b=UW~@7E#>og~74N>>6lQoJURcZx z|C;=e%$cuiMTzuiI;Xv|_=7YN)^1C&l|}qTa%SAL3nm5v9O|D}pHT(g;^j~mP*{5u z&z4gfabakmOCx5K&QoY~_=bRpYahY3+R8)Tl8ui};TPHsO|9`UUS@jY5>apDc~qbMj7@;=;;zq42ysKQ9zZC9$xa5A|Fc z(RBnCjCj3rBO`(`J^t{R7Pa6`PWMb!j#X_{Zm*0lj!Ua#b9gXSsBkQTrv9cTcd9@) zFKc6$6_$Lv;wHUs*Gki(-mUy#dqxJgc!E>c$gi+GF7)ey%8!ycT#L)b0-Whzj&;(O zEsZXG{ONury*WkqsY&;=NOnZLh*lim$AcvclnC{iO$Ke6)Ke^epV~S2q(SXUjms+^&07Rks?O6--Ax>Y7NPT* zKbl?zUiDw(pcF4Hx&Fa~kw#T*t`$h5Nyw$M54i3Eb@YK9u+W^iM((`8pyc!)M~~IkJGjzd*ZEvJ4Mwsr zBMe7t-%)p``BcID9Z=2qJJ7-Nm2pS(uoEq6T6V}>(v{*}d$j$xr3 zdb8@_+_UuHENQ_ks~_Tr({FpxQJf_)ZBML} z@~6P9R5I~8=$JjX=g{<{w>BSJb@fZ)iy@7`MqH8hRs-~_+|0YQ+!MMs-w$2gS4Lc^ za#7NWp3eA;QFm?-0{b6%v|(UdSJ=JE`L|=0mG9MS`QI9mW|to@jHW*2u17KW$LM@D z^T4KSB6j{g5-Xbg;Qk$fg7#rQ{?%s%2EW{-V{5ZoRM)6;puZvMekQsUhAL$K)x4zZ zO19^CredN6ia8mZzN}NWEGOKpR7jpNy>z8uDnFadUYbnNQf$~@TLaIdER7^p1wRnR~U(5+fMRB}4N+d**Z&c)jzaIg@ z{ZG#C25ecyF}J0h@<}gjY)frum+qo$uRn+sg~2;dPr|G`)dD}@6#RS0F+e& zv^sE}W*-y(?vodkLqWs2wDxY+9Jd}K^mFeVPd5E+lt)wjoph4Z7PH?trlr_b^&hg^3#d0kW5#E$IJ1KEDJG6kQE{%vLYtJVLjl?k)j zD&%SZd$hFx@eAD^{Xw^VdH;_#|Eo$Kz6-Q@aHo`IO{6uubAQ~}9w(09{VIHyA1)IeH zSvj->Z_^YQ3tD@6rZ;S`h}i$OEcXu<@3sG@NB;4z9(hb_XU%`Nc49<%)Lpb-{;yQK z>OWZF7xD)H7yaLGwrAm2pdABeIsd`ZnFWL=$nDb_d&NK+U?<_HD8a>(&*=1_loy*I zx!>Cqe_IvS7`b-FP4o{I>7(?_N?4@Y@%n8Y!mVy8Y7Vk>D;e5Owrv4eEl~4t(rD4` zcW!?~yw~2lnigVOQ!6Q;M;zfeLavOuhBIUPiINH{Mu5P(VHDoP8=Z@nvU&0%z|+N? zIz~WZjS-9)s4)+{-IAV{_MUNYL`LeztRvV2D8rW=zz`d8+|g3>wEv6lgqKo@`#L?g9A`YQy`x|7kuE0A(t>}m!Z!6S`A?3Kq z4~p%k{Flo2raN{@110GlV6>X+qS1$NG39FcK6r5nrBPSrR2>P!EiXT{LoGVFcaoBD zlg-xSg?fsm6dy;mb_W@?u|nRKJ3XZ7flnH*YUNVF;(&waw+UVmhqXHVibD(k#lZBPmDq? zmy+H!P1dc_jt#(8Q+3w(RO;Sc0&U;yhl=^!*2=2D^6_4Grq-0i@+RO=RlPk_(tqz$ zQP{GZl2n#3eG0a^a(K!Lax5}7jwRhQ|E8lB}w8IFXm<&|a~K<9}mxs}Lu6jhqmD2@D-Ql*{z`I?O^ zXc(~#>Yra*BM(|0&E!(O9>N`Ih>UD4xuf#->NrZUIKv_ZAzD>pn3%#;gJt4x=xV+^ z%2L`8WDthZCFfJQ(r~JJS8tFpRySGuRY+9O9BF>pMsgi#JSEI^k{Xv@)3DqtIzoER z)Z0eVwM?2K#!uFU9A>W}tE+o^Qa*I@6}{<+_MkyYUZx`s1zdVA?H#CH)2|jC(FD!O z#@|-c!F?j`bwMdyKPH~_+G)>E)AuNRUdAF8Ac8-{6tsZSCCG1jll-qU;=kH zUp9u{gcDr=g)TRLiRP7&=*Gu|n8wb8JjjKaO|HO|(|~0RqxlQUru>1jCIHIzpY~w9 zsxH60sVIy$74?hmJjR$+&mYJt?f500Ylb&X2Y&}G?*^dd9SG$mO;i8ATz}4k(alG8 zZaGL@m$907m=uDS8XV;nRsjj(Qx)r4e4N1oYzz%#!8edkR-(~9WIu{Gv{v-(yak=7 zuJh8DttwrgIoz)!WDcUD3U5j;uw(ujxeR+W3+jWvU9!~CxVIw6Bs=ByigXUEgVALp zZ4^~-pBm{Sg-34a;<$~Rri0u`Ua90(s3+eO$(nL)rov0)Zx=Cw(bhRzRYVZTS!aDm z?n2_-?~z|E^>{q-@ zGDuEHOzE`_NPr1&bg_?+t>{%)(jrS5x-JlkxM8KYme{Qj)K!b~Q0Y_B=V}ziFQxv( zNx?oIOL%R6`_0s+Zf4C3T78b|;-J^<;jZ#M{cg1rt_LqngsM!e9C&dAmGg0f7LSHe z92|Or&ytYFaj9^d#;mFJaPBw$v1uO7RM)E}b9_}5*paS6T&oc~_Azj{xHK{rO@*?z zy3{Dl*nbeozEf(YoqOSD%f$_-H6@q@pWUHi-k}tH>AyCU@erb{DL-5y;2gVDsayywB@>2MP>EJHkSZxz22o5feW7l>=8n-b|7}$RtYzxcvmHv zT&8ha!*r78epc<$Wl@XkQq*96($_YQp!R6?dN3s3`RYXP+1a9;jkQlX9v3Gg{alPf zhvWEA&WIgQ*5KP)(#-TYJyG6o$n+=pHP2>+8|zaAzdPr%t8@=N@=R^ZZdMNo^Yg+6 zC9Dc|&$c2%=U;tL%_Ho?^^fl#uX1%8M;qbjOm}oUkJS~;tz7%`noH2o z%%ZM;qyC=0NS)6WTm~r-4mJB+bAzBT$@OQD61UjeG~sX`j#j`;HXCpx=6(A(o*7&` z#d}-qe!OtmNUG_MhCx9)*y_~=+UYrwx;Br)c`?OPOYQW$TE1}T829<0vIh8D{xiAV zqIygvsC5(|VUy56UhkDW4c!w0caP93S;=Q@(lL7|{tm@(&ymjC{ke9#w_a*Q=r7i!gdx zl!~JsYs}nNVOsirdt?~Dp&L(U)$ub&b75k#%7{R=pz@R{Y_i!rR9*p^PKK4odbk5ptwJR8QI3O7~2=`h=V>P@x@{^hM(cvwe@zqL|m9 zw;s8jiqmFj!do6-13X0w<$-adR~EqAgL^no|MJSI;)~pag?k{{j`|yRw+1M$1SX{o zKI%WUpg-)@(pN2e27zl{ix+WDqUQGuzVLfx?Ra;`M;8w*nBHuIp;QIbWtLu1pMg-N za9+pAAS2GUB!48Y=Vh-d^1Z)1qJUE!L=?lc&Nq$9t{t~xrbL0duGIC!H#RxG-qTV2 zAFN+pOF6xqo87=u@_WVz5UJUKVnl$d(AS_UwDND_T?x|~zj(U7JNrA|4nD(q!_w#) z_{o1Ut^dZN6n}};(myQf+Bu5~e;K*QyIXi{ar&(5ueh#+5!Y*ebt`FQ_osoGn+*lb zWdU%CB1(V7prSD`DE36OSnSz8TKcae6orYZgPX8-Q`8@PT9lU7Kbi_}1g{?d+BC}E z`xAGcJkvV{JEGy!u4&pxhCbm^=w#lbqTS6V z{s+tX^2fE8N$X+9QdeW0J}w4c_m)RlH)g%$OBuY?86#upxd$7nOo`DohEoZCUDB^) zWt1k6m+C;ZX*n}1f0~O?6LNrt@x&sd@I_<~I+@uglHbI}hrcfh(5a{Hr7Zr)73CSh zIWX0Oi?t3Cu!ij$d^C=IQu&5**hoKu1(71xdO=6{$7$Q58)0h}H2tch)_1T!>=KTc z>PTZ>xtwDnxK}6PgxpEi%y-QYVpUO;-IqVxsF=>+{c^zf6a$SZS+K&qf zbb>Z~zSioZn2k#VOXXX*n=&GGxRQI<)3>E-KWDhs#wJ850dfnXk^JzhC)y-e`Z13@ z-V2e81~=+cs{(hCc;U&XaWSnG1p%LsxNKna3cG&EWFji61CPRbM5EX$r<4LZ9fie^ zlxG^7g1bvOh26r=u$w8_M{P1N%2F&UIFj!spy0u5ee%O!B_MX{vKMWHyP2JU3j6Dy zOLJZel^O$Mlv5j41J#N?PB{^a$gn2~w`#GINMDI_)l5(?QBb=vMVqx=mV)S0UMgx? z4NZFxN`vpb?osfX_=^tpey*$DwVJQ$Z}6|HdKboNbU?YkT-)kVB+fQXYcDWdOI$YA zitsegt**TVHK8M4CqTqob)iti(iD!!=&){8ht!3L>>=RXqmMNuoVF`QGnM8O$8NE_`DA)vU`vNo1~r`@%C zh44qQ>~QAHq!gh@(bfF!?vxZyXFXBDn$YD1R#`2VwUU?1=Hl3ew8+xJ9Qv!B>|#FR zT;Gyv=V&ugr$1yJk^E@wY`nCN+gjN)inPM&;quXrY1v0(Ri@H8%1JEGTaU)xTZ<74 zQJO#*$ycpKBx$SK2?S85g;M>V5s!hJF>;&zXYp)%#L?-+(HGgr>Y{@(*8F70-wv_R z<_XD&@$=!4b&ygo|J}5i1zr_?#nlVxKI?O27081_&f}Y-=P7kis__R2W&!*s{uzF8 z_K2t#SSI1enV77S!k?^C5BcA$(*J}1fZUB(2MUh|fNWt6%ncVCFrAyT+xHF;%sM5A z@v_C!!dw6VPxnEs(V55TIhmO>FTrt~RVByc$HMbW9BWS^ZfkCMijBOgd@z;ux)xk=A*ZP_n&e}6I_M?%+mvIv9>E=>0xJVL{p>(G@!r_wV?^veY z`8JmVmtKW)5o%s2{*p1F&_R{y=uCnas0Xv zhsNX_cuQ${IYI_othHh6_D;9Bs@jgF(kmafVxd>h;fwCgw{dCtshfpk@dr zI?&~KWwb$UoHj3W+K`o_svS9Ab`5&0J{$$-U?3YU6gXr6TI! zV&pQ{6CG=v_`3`V6jc}6MqHjI>Y`SnTf}>8!#G(@zED=c;vdoylu9zI)MFigl-r@2 zT_Z&WcB&ImuZ`97_+?WwMr74h=!Gi^d_}r!8y^Pcq-Lsi&XpLyRH}NwjGaT@;8_FM zim?*v710#i>wPRNPyCU767kt(R-r7st`vcINH#kH&LyE zSwTW})?@{j*2T?u4Q}s2@Wq^t_TO?%q$JG7m@s@^7l%F8w~IvJ=~}2M=-0J_ zT);5h=IUs@`Xe9;e^Y+RWbJ`xS#U9**@;fNQ+2E#HI{^?x8n#TpJ8;Ewu-k0PNkVM zk`RQ7iaTi225Smysu6k=^s0mJ{BikX{X4Xx_;;5Jm4x>hA*jNDho`;+32cREZE*v) zO_%GONZ8PMoV^_j4|f76`Va_kK5y7%qijwZh<`6x+H1g=yj8RyKYl=f`dCxo{TZEC zk^Y0pUg?mE_@!#h6M9L~{5`=@R8BZkDBnFh{A%cvsGJD0f!$N<) zM{>OzR%Xn1UtT8g#wv7P9W4GBN@tx$86h_^^4+lN?XwWc=9YeCO`+8~mLg7?CC*+m zYHj2s2(^!(xD?5UKgnC94J>>S`#{D#;BDQyF3?@)F-n%_9NC#%%r?`Y5yv5Z%{TqI zd;UdP`_~>2{Tk|;XG~Pk%D9lJM0WOARSjRHqZBe<^AbmiV0BPo7e@(3Chxgc7XoYy+8V0_x>+jm#|u_GkaV5QRu&FG9~`&>UU`- zCv5Sj+VOHzZ-HuFDB{oiYVU01Puay9g;gcK&BGTlP4CU1%1G{@kH9hcn&$ec2J33; zd6qq^PhMh=`#-xtzlg-yJ+)uEK#vcp{<8{?nFRuf{1IyU_!Z>h1@CO6n>`y%vegQb+^P=~2zhn#oGgEoLMvkQke3_m^$i^0s zqBYylb?Ef5n3c2V^q#*jK#@@ghO`|>Q#;%NwU0-{FVT;9L0K!T8w?|fjsL}Xh`+Ny zV~4=s^a-37{*=5&j{R$;(qiMk8jQkBXV1&taS)dwwZEc15=}#YL7l?d9y*SWmdMz$2WbsAh7N<_j63$(S{!oZr zd`AJ(8^KK;Mz>3PZ4WD{5}Ph=emlyfR;I3ud54_tVyE(!SnUT>P?B{#x+(shMT2K; z{f1;;b*ZQ*vy{KD2fC|}nMf7V_*qdO z@?cZ{-YFDT02!+ohd+`qzOY-O6m#<_OW=b`b0le>8Nq8>MzU*3Jx;6RwhEk6Pl)%y zTjID?rw`+9Hw~;W3J*NkUmAHksd8)jG7lM5v|#y1Y)JxfuCs`@OVvZo{u8C@F@^(j z60`y}m5xlY3XLK+Rk0A^_i?&#-MUp+&2Y@S01G?i#JqIQq~Q39qNAb=FH_W#`E^>qxhtLhRd-0l zJI10T@fLp;ys2}H@Q)vfQB~N_x9?Z>Jsu(Vagq{akWp?>pn(bsMhBFqU zGq8zpMVvo5-9mG6)hyICpYOpNt8N~oWS@0b zyny5Qnnq=@`Gi8twv%>3xTSg37-{-H*LtI0u77?wn|-Eub=C>edY(LgkAQrI+k#Cep#K1L z*R(hXqUc3M-*3}nqUUBsG0mPSApGE7USHMd8zReK5Wjw53F06tH?NerwzFQ{WUcb@ zjdY-bNGH~k<2SgN1wp2j1#yU;ZI9ivs3qJ1+=#Sydkb|80*RsuX?8d++0xDhd#m9( zunEgI!7j!GG*0SgawfZZbQeE9y^T_~aCpIgxC5{3RsG@;VrKK&%V;h^8`tqk3v_8G zQcW?;{_+=sNxa(+6+TxqpNggr)x5Ns|Gb$=JIeGv#RdJI+(jQbzf9uIj30XHLG^@5 zp5O-sBjo3hIUyui>Os)X$2z@zaSk=68+Sw-k{PqI(__QFO^NgMxri)rL{=t?= zjw=sedShYMdlj2hyLS4}o3zF-Kk|;{TQL3Z*B|GdczMaaY461z5x*t#alJ;9usp%P zN@Q~Cb7mt=7CcC5F>?LAv@GGe0vi6Z{mGMerB>JC)erMO0Y#~U-4Q@B92N`|Q{RF_ z6|%%Q$0+QTDF!!B+W0lvlahIne zn^NG9jPcvJr9{49UOQH&m*G(TGc}ZByI*(os}~~CV7Q-qsG0aXLCp=iK_4- z%ft!8B}ywsc5cA6MI!EP>3iD7zGU@y68)-OVM3uyF~>?ZUC^v)&S8F@mKZ)&m&@De zEgun`udmF&`_<78`O&}sk@Znsbr|bRk?#O@n=mi4My(SGE8#&76!-havGzeDWqrcP zvpe!;hN%IU$p(NDRU~4}Av=)LU8H$AdvjXp&1Db1!0U7ZzyXt)s_R!)eZrg(bRB?GTrm zHIngkIA4}nI2I8-Bvs;#dX5@syG8FOp>qsb)4Rfy(|0X{o$BVqQp{9wn1CD&b=&>d zO6IbR7VPw~dP7+#;e}!=5!tco0u4JeI$vVKN20@zSnq{z8Vt}AKd&*NGoh2D#&RtL zwZ|j@sm*@We*FE5yCqpUdlsVM`Z3E1t+{>tNL+RN)}^#~kG=q-4A2VPDd7Zn$j|p2 z;@vWNlXDi%&6hnK<>>;-kPbl^(u%@WhcAm^AfOiM53HCj;(c^8oWZB>Fd3VYb%?7( zULoQ?)$MAiVl&{o)Nb-sFQ{DI{&eks2>b7Ns{j9g96$ER9!25E$jT<$LD|`R%Sedq zia01lvJT4LdxwmYk-al3GkZn$I?nTZKT@yf>-~BCF28@A$K&A~mCkwGulMWiI&j%! zzSPe?@3i!O4!q^>7(MamBIF+qc?;q{RHH6WFutY0KaUZN53{%p63q9w*6qU&`b#l7 zfpc<2c7DHz|LzyMB65AA8Uup&TrWpX_}cwK0*=SLl36|WZlxH<GNWc0EuJl+gGc7alD zrZJwiaDH8$S;6N~>f%FVi}KUcR*|bl?=66vV^cAPh zbCohdeCB`jnQUeAIwJp0Q+j<-K?&UEe@#38Z8mQ|&&~Yu+onT`&dqErvH07SUcC13 ze}uHdE(X|tf|DxFQ`;@>f_Kqx(@y1^)(9i`$Br*=Kq`BabZiB@4A6$TlR&y$0|I|` z^5jts0E4D|6Q2iK*A)$3YAU9L!oJpLx=%V~>HP0JA`Qy_8S(yJX>Z#oUDBZ$Zue>V#@-KNBpp68K3_Mpo&02i7*$%(e_BV#hsO~2g-Bkx{Xn$Hpfn|>LS^h* z35{(i!`^!Ct|<1^3PG-X#wfoy-E`|N?6j6r?wa01fe_&m?oMkQ4aTtdWjp?EzQn>h zc!+2nCWzZd%5i#*Zsj-*7BQoW&W?<1EBCIsTuuDr5b5emg_kW!@b`)l2Ap~nucJmM zK1h*1qtlDkMg|-$<+m3txoM1*<&Hptm)Gy?eO(R?R}N6x9Um*$GW*s}Y?P{1gI6|G zV9C!WtUH#N)adQ77#!{29Ui7=Pxvc6QjYUF^9_g?HB-M}aA%%#o|-|HQZSiXQ$Ix5 z;oyden_d7`GNDX*O1B&7LtXdD471nGs~Zj`&PpvQV&d9}ufB2LCGQzVeXc0_7A6}G zam2v9nN9MvvxFvx5u^DqGe<%qW6=DINyWY3$#6fpA^~O*DK!;VHpb|q5qEKa0%n-8 zRzt5vgGt=O;8!l!m~zNw!wK_i?%aZOBG=$m?+0aJ=9#4`ipI-<<)+^iR(Hc~yb8Y< zw#qyp+oX3RHt~s#hrab!tTqT-jD1(?;!8}vToI%w%!M#D=5MyK744TPoQ)G@N!Dw7 zs~qIkYE8#rANepK)PT{aguSbT#g5gn+qiUaS{O-v9(QC9pNc%z53;j>cN$w9>KyAfzNVQwFYw7gEA`D_EhQbl zL(mJKZ=pB7@V^&|*ES-MJX;_X{StiN1+9$iu{dvY)Sfvrg@u5O^zq+hqD8=XJcNEQJ1B@K3Sz@HERY|>$<`*mrz7Cdhs z5o$>Ltw%O}IZFybX@APnr~ppQ7MXt_yUift{vQYd)<2K|9Aux{KM;GwCm1JAZ^%&O zMmMw@s+so{44rBwP*2L1?BVD~(*C*tx1%)}=i}64Eao%^__q;Qtc4bM9{Bc0EYwLB ziURyNNxZXt(+{TgQKGOQp{Y(>m&Q2gw^-;m=m_Hpz2x^^1M;^^l@Yp9dcS0m_{B^0 zM8)M3Z4@!;BQ%@7TwFih+?!StOB1t;*yX|$T<}FDch4MEp0Mlq%^_7Hh!t%sil^O4 zxR)Mf(!n{OUy(2WrSyC-gW7GtFjdmYJtD~>%F#$THcqZP_trk$a}>2;ilG$KgS@Uh zj)7xmQufckguc*HTxJaS4x5hG1UJakw?a9$6zbL#H0CwdiJf1@v&D>?yj7o|O6yLd znrT^%Xgw%#O!7>{e2Wpn=}T-Gb(`8!0mufsq~of^II^w|$0_r)&C1@a6{G2wWjI?C z1gkq9aJ#GoD!AMx0%f|%+qeHT=nPk6c zyu97I0_JY6nuXPj`Qs&bvlvrbs+`-&?eEwJXt+to&Tw0IO+MMriLniLgLB%YS+x>; zj(JMAeQbR)bXYQ3+iucxuSYb>iO9$x>S@ynL+toSYO!OgQd*T*BrV!^rT1!=WbNDcQZ?g-3C3Xt5danTIl}-`^^< zo;H$|kfjUwYS*Af`y@;H0ija6U|Q>7xCzVl0F~ooE2harN1MCVX;!2Yp$sL7g8)`- zz~_%5#1qB&$55=GX4?XoUMlnc4rPTi*k)j|MgR_!0L`Q?eDCVpJ)-+Fu))Ek&9Xrq zZrFGuKv8KT^5}qazrp!W!;z(bBFULRvp1MXqDyb0#S@L(54tc|P(Qs777Hi~N|-M) z$*YZd_e0kIf+|)ppH)W6oStX+sDrJ_-K+p*#1_e1estG@Ma$)>5$ykGSCk8OV*Q%Knf|2jSxgWbH1){`8{P7vx z@H?Te?d5JOWHV$|9s1@@{Y3Rv1k=*cQBG9fZzXBMXABRN;_}op#OAefyQW zpm`w%M}JFyK3uANA3NGezdEjegI7dwaYL7}h*YKVVe2fG9t*RiSDq|8ak!qE`<-^~ zf?E$JGoGBf@f+PE=v;BsGqMQ}RARKzBXWv+^L&6h?()zBPKRNRPFiL2mMFV`@R6-x zDUKuo0UVFKj6m;6j3&CPQG9qHD>9$J@(DGkO@vGa;$to?66*^TsZz-*3T*Xs#7-6=S3+}X5k`DhaWII zbrpIe*F}3>vh0BAS04HgVSaHoMIE>pYf@bFw($~~IpqW^j-sdIN{Op2uC8Clcc{gP zWX?F*o*Y`1;|(RNuasvaBH~_qArux5$v5mVUXHuZcFBU%OGE^LiI+_#13?pWgT_+kyeQuBC|p32nl+)} zgz!a`mDZ9?#OUa!@Ng;Ey&zAv4?I_J=cARH=@>$)t*2Gu53jch;7=lA@<4&3PVHzOV@{Rx z^W2?}D6DGdAH8ue4edwtLu-88o$lAg%ZPYrb-`poD!B8)bu4ys|NV{AOFF(+If3LI#NB(Rj1f~7&uL1RwQ`pECch?czJ z^*_Vi=*Dq)6W*>+Ra8AlATLEHkgITzJp0WCqN8yl_`^8;p(ttAKONlvK0e1|DZXG2 z2Jo21qOtHFY^JfOjS{jBJvXYLcFwbLT>rGxq@NC**Vg>Gz$N~Hd9cO#+^O;p#DMe% z^0jd_5ICcQaB>KOtOk~jTZfC?KAi|V#7iA$~mFkCvE$TOOBq^ zsyRvPqkDu39~SI(V*I>%wTW+1%9D++H;T+A6b`!AOgWuyVkJkp5%l}Y6fWtgnlRTt ziPPfH9+DCoiKiD=3MF@}*^d0N3yC7}c^*De@@P(1ZmdTC>Pu)-*J2$~6k4K(>Pl{B z8y3d3;xp!mfHMz+DcXKXYiNMLvD@*@0g)8^jq;_x z$n~D32$QGA99mh?1VrKZj3;FF)Ne5Y74Y^-M>URZoNiV>qGiZG@ofpb`;?(W*yv}r z&h8z>ALhO!1-=jQ5Rb*JPfKM`o>`=?_VZn&$4u?A!>;W!3%QM$B_NvgO@#Vuy0w}$ zVMLl%cYUWF33=(JEuS954@E3+=peUG^lFi|dCILPjv1TQE^s*5T!V_c84^OmZQP z%Gxg)42q(*l4TAgy?xil_D5`FejfXGy$_Ua9DTxd9Je;#Q`^K~?UG0NrH{TDx#8Jq z*oke&@;oAh9?rx0)ag3mYyNg`y7{o8o3{!OL>nEaIU2Cn_xcDL!fn~b+`g9Q+PhX^ zq$U&sKlsGtvt@}U#>mdFq2W^NU2HcO4MGi#9MdswoVHL-fo){d>0{`do#KYdJU#i1 zJ}!Bc%V8CL&7+NkIv0>|m63+~NW11-wYOioTo>+#&36F>*MCDnfS#dRXbs=tZz!0z z-MX5Ayc(pJr+llkC14=0tU=gEcQcgkl3PM|%Ddwb;>je@#Q+q(V zYBXlCjRXP04|~Bsn*x+0YV3!ArW(z(Gtco;a4CKCm~>0yoP85CgMVr~A!e;-;8@)~ zBPQ@>Lx+{;b-G~q`#|sV}D7UTxfEd{YJ1oT_OKZ=zCv6{iv$c=~R^V3qN5D6;28+9Cu|5M@ zY|aoBaOm<0CHk)lXg2s?mQD8^kRO6=#iyB0bT#6m^J+v5yS4uMnJXx)<7nvqt9{rQ zAl`t}}Fl*oDeNtE}IxTBdMZW9W?p(j*^OrE4YI)So{U9v9X2knjY0y z#IZA*vJ#ovaj+LLXOEN^ciU3LY0fh`Q=9teIr%Q7;?~8DB3tl1`e)Jy?s{Ksj#zpC zAMNgz!kFJ#H9LBuqKiO`^pK(klSkw8EQl8Q5p4>)>?ofQ8ALmH0z7RO7+of?)p(Kq4TNl<~zYVAKb$spdErF<#Bjw znz8AZwO*5OkGe}Y)8}25hYBYzb@uDV2!5}M8Pb-kfE=)VaY4xNb!*h-7P4|(<gaSw+S8-Bio*psg#g7c2O<$kHrV zn`5-h(=d#r+1P6y7SD}57S2=CFU&r;E#DNwNU$)bJJ{`f8I%ZImte;h64wg(BNU5k|E?6UTxX`DpB>v(uDBAOfkRRu0sLEe6q^ z4xgiM?2Da}FYtd~W|&PJqd4xW+GLFQ99DLgJgB0Ze7|hMm~YLEW26ADP%QoiHA^~* zO7E8SwZLSb5n>1WCa$K^U=~fn_oO)nwKe#v5ZBb|7p_;ohTrEOciQGm5mU+zjmCbn??DNFp0d3D!7iJ~2y><{nyM%x~2O5!dWFt^p zeQJ8UN_qzN#^YHV{3o}89SID%)>-jc9Z?nwwj_paT#cWR!AsB+(w-A|kQhr4z2W-1 zC=#XlH0M~~AbyY_(|EGy8w^u|Z>6CcL})%WzB#7uW7zuj4}^(p;CeOtVohv!adI6? zjDn)h&oEEph-OdNc% z_U}mdf~3M_;PZVb;d?(5aBsKIpT+lch8u9XOJHMTYt{{zD-YBd7ZnH%E(*nH6j%$P zv(z)JL{8?>(ID{v!Jf+#tH3~;5SUiZv()2*FAm=5{tvS?K*MEk)*8{3;2|ylViW;_ zrA|Q)x6je+Uj&;Qa?z{!mr_i-2ve`Q@TXK3y^|vPFG}%)#r`^|%_%g27o8hafC9YC zA_Jx8>4$so#ZlH;gz>mp;?m;vut{9&@XdZaztKiYb!9`ZM_YCN9kul9g6hLR%EM>3 zqCf3MM>csA4mQ|URRiVV`*0)leb{Ujzff zxzSHMyZdQF6u6$JcaJ7Wvjv;%@gX7oo%}a770%aJVkB=vQDIbX|*9%aFFsGgs z-PFJKT~_((y_~Juc+WG!&nEt%x~xq!$|KJ{4??vz;6w%q4)yZW(PCjg1oAeOJ{FN$ zuWvjp(|Y=KZ+^OPQkHs>o4Dm>ba^w8;L$16J6vc{amsmR|HqROFUj;Fc#x-vIbppB z_kpq%AA@dZEBS^CiC@*LS)bv<&64p5S736IHIJ+g3SWNxx$V2QSVj{jVyu4umteB< z2$k!1CU|}UqG=2)i9XjCJY+}DuWik0q5lILMw8gQH3BT9z@ z_cfk9$LI|!yr-nFcuoeUD}wP(A-i@EL=SndbGM>gc330nOHapV_*=_O9XO%T=svHa zAFt`fjRIW*RVxP8wWWh{+O^`_=_msUmyb_}JZJYFEEOdFIB5Y)U(dwRfZ=5Rvw|*B zj7)6Ak>$8D@nYXpmD`jF_s3*pQS{O54(E6KvG;}ML(??b?f80-^1VI{`lwp2B~gn5 zS?tJF!>%DGm9dIfZ9{R#%r-zRz*o1B*8fJ*K&Dc+ z#;jctJMoS=QQ$~x;0@;_gA~^zjggO?tpdr(_msCb9B-Hy)Wl{#kM8V{ld=yuh*ETz z&Ji7bY2F*7)G9)ezCsFBAEhLnNjt>bEy#xR*D$E#Nmmm_;pn02FDt$F z8yYyZu>wxS416R%qBj&xM^)2E??&9OPI)3m=!SoQ*SM;U$DbT1OW)k4T(6qLb?}*X zgT@BhQL||D-Sv%-dGK(7w(h9t2bMdM2|t?}wcn6$*Qt}v+84Rg8R{jxWe5skTMw(m z=3qRPLRuJuAXCzF*E&kLW<4?K@A` z04KV)ss(L08Yvn6m3^oXdtm$YZyop_5d8Z8C>>!tfC;_YC<=3mOnwG>8MXd*GdR#W z5&$V6vK{nf0G*>e6$bTh&$J*)3dpU|p6Lp7S)-oQe=hV}P>3#~fQ#C!4rtXM9ihol zFs(foI$m(4=cj4kB(9*7A%$kP*BZBKcBp9qlKfrQcmo{if=Wr?T^T?=0|r-+7I{zO zQ4;8CL=T;T2L6wey7I4kB?;|b(E#q141jqn0p{&GH?f>x|4-<9d69nrpm5OKgXTta z7<0%QKtUs@1J`DlLFYoEQ87c-x*EkH_aE-_-QHQQ7-5vGb)S9n1s$4Q{tH>r)TBm> zQ`saPSZ8ZYwY>GtRY%KX>uhTa*LAd)^IWxv% zb~;RXdzC6q<@|S9#sbRnhx8TjdKjl?w_)=m;=a*hZAcSlw}6-wsrd-}wb8w6O%;{1 zvvdqEJdh7cN}_A3U2;T93um61o<-SwUu$7EAzpkJ3^}#2@vEAd0@-&Cyr;h!e`uW2 zi9%?=*2Y8oEC#xT#w1}599*VLxmo!6Qz+8>BWGGI&$!Cr*pJ!U@>xS~Y|| zu$?Vqs9RM%7{aGz-p=8q^bt%|aS}?%Igls*OlWgZ%qQEYe}&ioHt5)`g?!Q&dUJEW zWb>}Q3dfydeLY4?t1{yoN_gQT6qvZ)Vb4Ua(~z;JEYcItYYoRmTOACOU%r&sr|R}` zHf+LYB%U#wXs(DpJKCQs^|ea0evCjkn+fFrcXXtS@r{KAujUf&Tek%uh5?brfhR1? zEFfy9N{h}WxFgSDB}peFfhKXRRp`~5%S}r759g;r$u9GCjdeAFz&ak~li?d;rq2@- zUEmMGr7j=mUDsY%Ms)5Mpe7@6$ISiW5|y!&NAC4MZGtQdS7u#y+;Fbba$1xP%oF(aJTg$kV$+Ils-!T-3 zL2GK`Nv#!ToYlCtt!#ungrCWqc5grbVP5Frb4G0Ig2Iz9T5TbgfEcCypJ!@{dBtB$ z$)T}fve)yezmY0PBL6%5&XnFu+aEq5tiAxIg`^F?t=0bnsXnShQ>}k9$4hE{ zTd9rz4^j;`Yk7Y?o^9xbAk)W(_%`>V6f`s)@iEnLm5ZV*(_iN(bxK~wj@;cZaU9Zl zozSeHo-(wa;mz+zXB0MspM@1jMs$V?vsk_pl|j58&rq9WeWsV!QGy`w%k3eFiw&r!m|!j=ECri(L3K-UX_w1-QlUd*=UH?7u|`2*HdyQvAkAB&a`0#E4VVkUfrTup}MWl>7}*Q;viyD z_F)SQq|}bHb-@O5dTafa4M~F|->!uR${q;KumsauDpt!o)A@HWdNEX6x^dkosTh6L z-u-&D#ef8te+W^>P?Z;DAF)<@v&mPDK%`=xt7al8;x)QMX3UJ#ISE%( zv?rAzip*{1jm1!5dvp$m1dA~XMvM$Y_At?!I+b9WJkXHmj2B103?y*2sPMzvhvn$| zY8ZZyV0_U+D)S16DXNt#-=~^see3Re3P$bND=c>Myj+TyCm#rVK8`)S{@OoLH5AhQ zf(8^nY?RKvHA)7GO=lo8=LlVZmCVM5qyEKAS?J7CDPS&Em3F=q zL|YLKoyx^c=CPpSmR${JRvv3BbC74-VW-AKq?1~dIq#3H9@@KNs?m0fb{!Gime1>G@OE>hGc#U1?8TU+94e82aM+69d1*}pGox|v zhO$)9%SG26) zp&BD!;D1(Dz@^@rK{%4Odi&H>p?lxliT>#SzM8eiKD)%=^i&+Qt`jhPC-EqAWnbzLAz5(k38T5OL!WUKo zd*{VFj|Ahkr;YQYu<1t&oV>?RfFQ#KsO4iG9qn5jCLI$3Q_SzCZ+)tRU(4!fWwVvT?}^*8{;DLRHn1jO+Cwm$#u#wn2E(3pC3sIim1 zm*K2Kcb+8qCs0!B+EGB`Xbot6RPyn)*O+_+>T)7AN(9V7zxV!6Fg3636Hy&8=N=kp zc+5cCwIP201AF6`GHSK>r=-;cR^5%tkoKvFke6|6I8^nU);s~;!)ZM7+R6+3xHTms znK+Ws%_oONd_?_OqU*?l%VU}YFOvgX0~L*Hg!}S~^p;+jC_4*e#pqqh6(}|7)~CVV z9@sC!oYr<>w({lItG@P>d4&6wP{k6RC7q4C=0fsN-Rrp@jrUGNkRS)?NXQww+plpt zJK_Udt(rOfmIavT++q04{i+K6J4t_@gM~8c0@(3tq}|!ABoykZWF=Vtz>{9#M4f#` zp*`!*uGY~{%8fKLKAc@34-_06CFMmW0pcA_Y|owX9V0r0zbVQlGNbgNsxnt*t0epX<0LFJVee??}(Lzv28G{tOvAR z+pGx%gNx@PD6;a`_`{S$F|)0Fb~UBCLnL&P_l0RwdN7sRy)n!cf3U#=kYI%zMw2AD+JjOL_u(v(rxXI6(IGnv z9&EIC*wUJG$8HUqcXvnEJJH^d=ZgN>Cavs|aINo^X1zZjcJad|Ul-YqA8p2gYrYKI zkMHh&Q^8QCuOU+x>|B$W-=^*eZR<|viO;*tCgfq6Qtd&6KEg3guhLfMlvxI@pV6XUyDBfF8!kzQ5*2-k5I2p(1{ z*DI_<@!_~z)l%M$lyb2SdIoMtT(i|Ed8!<6= zdzs}DeA*;S{cfZMNJr@*!-bF=nj}iil3`m}{lj&0<2m|KEZt2v_gWni=PsWSlwKy6G_VY}ewUqb zfOEdtW~S3X=achBHr#+O=N;(*wro@l1r$(v8t8aR(3Nc>hpl6G+Hs=q>7|$vGzF^0 zGn{%|b|X?Mzm9&;Io(eEhSJlXI5P!xy1>Pq(4ihuQ*CAu^!6UGac4;=267cFgqh8_ zyD-iM;zP$$3hV`2GcxWmA;KB(VVxu5HYLR0Y(*uMP-sr* zZjSEpg5i9eDkAw)(IL4ej+ZNg9zc5ruD_gL?Uy(6kw`MhB{%79enn0AVqR1f1&!Rw5FxD(lGJFB@Cioe7^) z*hk*f*K@yA{rEblhkviA+!*_McC*x*@{{2}?y9GcIHx2kYuI)R-5lPVyjQUMh&Zj_ zU`C=mwcp%&Wo>I*oUyUO#k;;>FO*LrVsk>Gv8u4D#A^NhQ?UzB;4$Gf0ujC0`9WDn6m~ zyc-L~B7lOlM4moA!A@l0;k$Cl<8XDq^z9Q}m6`*J z;!8Kn@a|xQLP)+2P~SZK(i)We!iFfuAn~mZ!g+Hw+K3e?_TWHOZr4n1JMsoqDE>r{ zCInenN(+6$9BEu|Ig9ESX(1E-oCr$JE6fZYvRlRi=8WOD~+SvXRX4SsH*| zB*n23g<1A~aXoG^bFDen95wd$vHr-}Nl ziqn!PS`CoPNU}fhZS`tukSB{Atoj>&_eUE{(o%x?nVJT3vdZ17$s`|#Vjm1Ixkv@w z!*`QVF!o|HtthbB>{^%;=DAftSHK8vnVRuhG3mQA-%}U-Wo8qLb(RK}P1?Dc%ZOFT zmx{Cyw?|M^c_?WObZ@zw7%YebY#7lo>7E+y5!y?yXIx!T2q>_2H^5OP(zyljo?f`t z8RtHTx9r##e(?{;?{R={juHyRs5E1;v&_z7q_xNDZoWEj723j2t~5(hl%9kgwx zDaG<6de^GGOor)bzEcGXD0Nv0bd0l%`lN_|y*scN#9S^(nqIgr=Kr*?%|$T!?v=SE zxleX|<9Oj?4&kwrb3KKH>M?;|9z>}G*@u|kh&;_7PI{O1?4?(jd&;|UxFl3V6=5!$g zKnM8Lbz$?;NbencqeIaJmw$(%W5Lnwj=2|1AzhUjjbMsYeU{)r|AV`~MV}m*m1biqrPNtFP-jpQriQ zr){sFr}^l+9YuGXhob-d9g42~2ez{Q`y6dQ`ZNDWi#dzV=l>v5v#s$oiS9=!tf7Rb(lleYiVJbscsZ^tP_I_6che;P!SpOF=L|F(Oh zn;jR??d9l%^f#03IOgd; z;ec0%^7QrYL#^v^k-xeFwODc#Mc&o>#15aBN#v15)jb8GrH^oH`={L5V>J-DC4m*$ zE``&>w*sJn+s)k1o zTQ;9L?5^=U%yH!sHt~#b4b#Hrb^SV=(vA*7P)E=oN^E>)T@SdQ(%4S;6Go@vRkMZ! zCO%j$3eLKbrzX71i<&>J@|!wV03V*xCZccL~^)ddPgG@b*hR)f~rFsC8&)g(t| zfmsrK$kj4O*mt|jYaa{)W!WOQvVNf=sp@Y=o6N9eq=Y)XaAL8>rc8skS3LZA^I^56 z%?K8?RgnJWg}vD^%{B$?WSvoR<)Jv`TUDQu{L7R1h(5@|;Q7M$uW?Zr-H-8|rz_<@ z37h_;d4QAk%ElGhRNgFA?-`gkhZGxquQ%! z_P))yZ|-kZZ{{p#e1+i6AaqMx$F5A@QQ@J6up(+D_ck1MOuu#hs5)MVEt@8JLFB7M ztv|0SBGUfLf(C2W@`kHFo@w}AQTWsrTl(6FOD@8z&UC8t>FLebGzSFA*QO{-0S{$u zheATPvrey}vO>^DCB9X#qNKuDZ6I_Mcv~MEg;N|?oNdbUEhP4b%-1PJx@9Sc{4c-U z&uZaY%|J-=a7giTo)EWaTwnodI0Zg-vc68NgHWbz=t6-;yp-{#v7_*lZwB4g;g*cF z&^OfjLk1PGhNjG_c7oWNPx&h(EkS^nUv2&SYMvy&63i3+^^sC_;jyJ9L>wcmPCD+OPs-2?-@H67uwl*V%uE{55%!+v-W7?@md*p} z&xMI}vP-xgK@w;feAhQP3i3P-6+1?Q?u@4Pe@1;KMQ*EDl!LpNq;@1f{1Z%EvJG{F zT!%jankJXae87`Jm9_Evq1R$7vj6v!%zvGs7NS<;hdY@(@M$cmC7)}uMa&sprST}g zESWz&FG{3!chGMXU}1M)}4ZG4t;|SMUht8 z_vNqd2Czt7;g(geE9r2DyRMz&;b)2f_Lq%vH7893cR*SN z_jORz6kdsZZLmq;(K4mC0VA`<9|p{j4pC;&`#`op3i=-RhmoB7wY`t&Ttq033HvLn zG;R|e0*Rd<_oszFHYuRV)#Gj)ZQchistd_O)gRBk)ptJSW~pYXm95PB(bwS!>RCiU zGou~URKF}Jqx|Z_=bE9<7T^BdrCK23!5bFK_v9rpOi_`#t@JT$T8q&uLf-1dGD|p7 z_=(4IwVUL_Jk}oEj{`U2nQ|it+wz^R%Ms}>cB0sz^C+sy$+m~EA?LXeXbXwS&iaXt z$z8{^qto#T`?aW6T|Z#5qB?pe@uRliCh=*c@1_Erkz;@iF)FfS2j8qIx^YGc2MZT7 zC!FkSTiOj;Hdmy&3n2WCk+?Nuo+tjFNdwMm> zl{|tU)na{2*foFk$o`fio%7{4&GKEx$&n$~-^I`_kD8e;COO>v#wtS>Me3%pYOpLI zcl6$@Q=AGyq?e-Iqt;k=de^}3ZZ>4*`t^#zgJw`{h7+q&Yo?|+#*7lK<_t4OmL{#< zw>P0ysM3wG|CI8wuXQJPRhfm{UrlC-Cwq3J%Qnasp%oM$hOO`!kcug^bmsCKDm6z2 zckI;Qp9N!7=-$hjG*Yl@His}KyOC=8I(WueL+B!{987#J;S+u^e-q`|O$NhI7LLpA zH(bN;g}jJHu1OVN^Oo@DAC9G#)|VR&-UMKj)mwzR_u)Uj~%V>r==1KfudjL`uj zqxT%=7WL}dJM*n7c$7s~?%xTfnG(J3j~DT_fJtowcTsB+;g7?gjfH5tQ;Ekyw7qU# zlBDRH!_`xezS}{u5fUYlW?`JW!?8H|JQ^v6m#S#aQMWAJ;6O021v%^^%Z;YWR}k3c zv88j7WoR!{3%CyX#X&~#89UNdU&esOk^tpt!q=|CuR^dUkEajHM;8~+eU>RwTAC?! zONsFL->1Y=Zyh^JL0)_-8meF9#otCrGoM7R8VEyyyK9UR#iEwqIH@boXkQ>Xc4!j& zI@`75_9RqGW?kc6oj1`zNpWg;qNAM81AXnLhy3&Y8q5zSw3a1 zz|AzNy~lVRVZU0tFu!i#6iqGPu$KLjw2OU#d_`#i>df)R+o4t8QQ@l$8}>3(?txC2 z*Mrc0vb^4XoA@Et!Ip9{n*47>ZlE(254Wg)80QLq?s6oqOgd(_c&d2x@%*oXw($wf zzS>*5mI2}OC&QHuC)8Ie7>kQ6jzHiLNQp181v4o$VePucxwdbAlBjk#07Si6B7ZFP zMSX{ngL;3Xop|yM8%G9zH@BmwS%@=GypaT|+W~J4)Lj7F!UB@c1LDEw80z-hL7(8rX=*oo?Y$&bC?)KS|bP)6y4%^Z@23*TN3;=nD5OkaSzYO*#1i(-KFLiJ3 z?_5r?z4&WqfC{sSRhR7KO) zpz|s3K)nrZtXC63dY7H{A%nmQ!Fw4rX+amY(U8CA9P+0f9bZt_EvYlNJTDTR&bIeq zy~Ai-1DI(x@5B0&&&9s08?I$l0*{Uk9_2_UoXdQRxvR1! z3%IZD$g@$nTTv-1JZQbjH-W4ZRmG~|60IGdwY`RFz~kg{Reg>IO{>wQ#?GH zVtVN<vigFDFt4=WFgrV-R z?Qw?cyD<(eaaW@v1>@$_IrXC%^e5{$y`Jyo7iRUiGUQ2KGr-=`XW7BW4jXOXVQub~ zHV_i&I2%6x@(H#Hn#Q(j_ab+N9@P$jNtk%4?CA~D>C}+jtY`2kSc=Y!>ne2V0s8B* zBBKxZRvNf!_@OS|jOHvQaNrsd#go}XBp0tIfQqTs+rq-ttuM{Rw3HahFhrLsic}Mu z*+qxnyxlHXvmx$sP#0T(zvexN&jFz6Cme=qkm!#@Jt34_0c4GT;i5&i9W_;qmQWSf zL{d`S^?E)g0Xl5S7a{AX1$@t$6;^RTsquyY%8UnTE?<>BpGnWh*dlG$@M0DzwR%qD~5C-073k$ zEcb9%2zwBNxA;L$Wy;s!S;m*_YP_z*-Ubgzo;;(4VwNjuWG@<>)`RSwvOP`GD@oB?0|h2)IxuS&sbH%e=yXqFS4B-Dk7Q3Eq1$LTZ{JlA7LO?w)o3t z_|Zb#=*LmRSdyH8fkjQBwaxrumFFEa*kj=*!mZbDfBwkdgs%*XT6!xKDt;F6=yb6# z%NQ{#^oUlcfViDkR{rkT8}fqtfqI%^toRULHN6;*@Y&=v+3!K34GDeP+4eXFX(*yb`4dVfsj!LI7ofRZl1FmT<1;V~fzF%Reak|D!Jgu`tbv&`hb_v< zyzmtEo#wA#1^Gc1f`YSvJvrXd=qp~5lAs||Szm$r)NVe-j8eo#*BJ;qjI7K9W)NeI z=prHevmA@#mnChjG45`l<%JzzdbC@$@VosMpp6Y_ z%8l1iLhu%JzQ{m!V-(oMEc4#nyvcL*(%VF_EBVa%`*;})b4BASNe-*2nN6Aw>$~EO zN6H>E$9qYDc?4$l`bWqUwPVulQvEpcY?qfg2@w!1mPE0)k~r7^C<_+9vKY3Dy2EYP zLx%}jd$L~|NQSNYyj`^PvC>dhrR>e7gwDNAtre*=jbkY)8T>bR%vAep&rmlSI7SXU zyh1sN-V28HzoYq3cOEe+Xv|JR?IWQaI|WN(RufP zP0#ZJ&7K|T8p88J`3pR*3WBvFLAjIG2m?sa!psLK@vm~@Uv&DpiUYHf_w8$^5j$LA zwlzq{u5d1w_z_l7X9q3e^Ia??r$u{s#pMHI@Si1k$Mc*-m(~6d8z@IW`vz}CDL=#r zwqAgWyC?G?2OAR$F;GUGVir9UjAqtzoKU5t=W$wKCBs^Q$LYQYhB{Cf^4bI(LZSpS&ZKtl5x>~&@X#Pm&j}+T=DGnM%jwmK@J|>GSFtl z?FrxKR%m(l)HtPxa!`3EZJgRtW{9|lO1rF(%-!H8Q_Y?C@v8}q_NIG6xw9C_S3eFa zkPbK)ps-L>15AUz44~Tb!rHv)98Ea~)q6sX4i>ldUk6q6Pc``nSqozKBN2P0W+s~c>QRvW)XWRo)``&@mt_jT)T}e;Q5=HgdPIM*x3_mv+w~i*w0pdH{cKdP;0iws&viao#CaKUtWg7PJo!zg`jVdP8 zYkX3#Xw@diG3v25?{mu$n=flQ`99=htqSUJBf~njs%8{7JtCLItlO}L`~%@}jMH?( z+}|&X&P$4-!NX#fBG@Yx|N5Xor=tJI<1F!LCkUM^10Lid^oNmgIR2Y!aa5RiGB|qG zqt4u&$^@QxIEFjY!MXJ#F}8EG_}G|=j5hOZ-|OrLi&P$aXAu;%m1-9kEGg*HK`m|@ z*}kQ?L?*k;mg7_`{}ST4YBc^!NaT*VzY@03HcG7YM8{x}r{u~d6{Uv)T!C_>n<8ZV zY3}Ic4PI{43d-a5%&#oyDmPlOU*#|$XR}4srHFjifew*!U|R&T-a-KJ&UxywY(L$T z#1@Oz&>Z3iBkX0yvDRUs-Xq=8+8uc+-#$>}^pN3)1Zz5oU8M=uV2F*pB|xoeX*2g$ zm}ZVqs-B;@R1EqWsBH>!52F@iqYMjlH%tQIgrQq4;#s)geNX(Ty{89f_&x`jBW)sE zVt~4vvwN@?za8H-5Ol_7eQ#Ecm(}<9p}wWx&f#*K3DMb4!pF(Zo%MdQ!iEFXDPc*4 zRI6YFsKifB5nu%PA^)JfRKu=qTi6f}hT<(4W7DN}ZP1z}y63y)sG(Kb`Lf!FgsE!C|e za>dcsjP>zIcaDRag1Y`GXbOpqP(1HJa(JNrZc@$O)j0<8$x4Ee#RJy|5+tO%yE~;B zQo38|<~cX|yzlp(v(6vtl7%eRAUD^(uD$m!c(E`+B2-%`!zeeCIjFNYQK9)@@82i^#gdy8iO zEd9o|HJo?+lrm>IC)CW#qsszDrc7GoYD)YfE@!00lR27YewAEpJ2;|;z+w&H#lH^v zA9wJb85mgM-?@X!|GI-;+=>8W(A^vUx`U7Y;|@Ln_r-$G&+nweU9x+|fZ?u0 zVp>T1Uw`m^^Dn+bQt)+y{vRu_EHL%{8K$KXE9(n4?brFZ?w_W|^_TC!ew_cu3x(=g zUakCxxK!s(Wwl2%OIQ`wUBX>@KumB7JItDU>dvQPD+A%rC3zzz62SE6!@N-s5@sG~ zLmQES9%hRL)+@@%GVCymwsjaoGOM4FA<7Uj9MV)bK$bh&I#qo<4R-sY{Zb8Ad(#t` zp2ZbO&HxzG-2e@2&;hV0;~iBL>Wny}ywJ1~|Dtm=X^}e{N!m+A^oZy}gSY+h$VSn~ zbw2;KMD9WN#zhpYt-l(6{X)Ro%&`bp6G@1^mFlRPv7}EqjNb&#!U9| z`&711-=}1Wk=nYfh(j>nflq%xE+(np8@kBKaeothscF>(w2!?%*xS2Vk#B5nKnQL& zXnshSbvWI7Y*!{3Z{7bslOS)^6l<79G)bUY?}SnFv_!o!{Cn2La>k0)7vP^*urJI* zljvnXSo5IL7**#Q%4tg+DfsqMB(QblcBWsR^?2zQLW`ch%sGes9% zd_Rb-&IZZrysxoJ@FSt#43}**5*q`(ms~^yF0gzI>oawb(JsgxJ6Fv<^`o{agk9q& z*rZW^V8gnpAbmb^(|V!m4g987nq6lCZ(@x7!8<{m-lL?aNv?THzL?^f^7==bOWOLr zrqAtONBh3QYDD`;y~jgqYw#>MhD^nC@j5@a=zggF5u5I|%793ShQ^1tq5`^EnCxuR zy*+5P&kKHTpD`MKWNd9EqoOd&fFH(iqIOVRVsJd)y zmqRmyV3p(>%|y8suj!n|R^5M7`xb(guKBCfvU%>??PU?`E5z8~&al@|8v_zf--!a6aL5Iik#>5%q0MA$u2l6mXN=_fAJ$T2(ZGfB}ZDJ$3JuS#1`rixWROOo$%A4 zt4)wO^T%ta=Ib+~e$@@}l#`u{;HcfwyV&z+cv&Z)ae$Wi;z!dB*uYl!V!!!o`XC@_ zlmB1u)qT^m*&y+ojKPa4Xc983^}R9FODL#kCpeunrUHo(NeHo(X@T%Kaa-xzN+|Pk zwIQ*=SqQzg4!Lh-k(_a6@MClOSkUAw#g^&z{qt)7Y(4<;-gyFG0fYDA<#rDA{34xAfljHwRQREd}xH z924bxh?UD<&;@A!q-4epFO!MFf$KgQ@}~wN4lRB+m6K?*Tx-yTq1vU+BwVejzJLB#$mpt zE7dEZdj?@3s$eI9m}u2x+>{cfiiv!)xiJ41)@ZK+xc%^uGQCjmTPNy)@m;kvW+_?+ z?~pKCd`{0w()og`nV<@dYb8W=$;BbFGz+T1En}4|Uw(3Z z$l0nUBf~3`XbHEK+1Qy#cQG5quJKQn=lzh(i$T`<>lSf&oGF*2IelD8B)<|COI_@8 zpUISKi)+^yhp-2TQQ4#)4573+%Gh&&b!*2v^PViKB~Db$M*ca$)}Muxc5>?iGN3Lq}SFf z^M@3zu$e5~jW{Xyc30j;Si9fS;8rh_?$p|wgYo^8hoDar)pLzxl^yW276j0dXnF2Eb!R**m`t9lk7{T&Wq+r582>ZpBKrd^+J+AA;>LIJK{lc}7 z$hu;TAK&QBR-!o%#ssH+uBeHicMleZCn;52lw7L9XOJ;k%MCMicP{r5ZnNd)yA{=e z-g=0Yd@LU&PKWPzhT_qT32TgrWLuTj?6N1+|A4wmgjXo{2RV9Zj}qp`D(UM(Bsnl5 z#6-Tjf!)>%AI|KtB?mxOb_nqHQgI@5N650uM_?jx;^{1%YmfLsr zQH=>4NI37VO!L9fohzn1*8_E#P|*Are^8o}5+j;bhUf@#F}q60q~B5c=zNbG^DBDG zuFxo(o*A)TfInISSL}oFII75P7#2-@;qzTVXSq{UZKg7l`UkRCYMjz9m5Y?sRSaju zp1V?TnAXGkrC>GE1-pa&%5k8tqWc$^=ooPO93=`w~W=`i|6Lh*P z5WYAh>fEW5e^x;Q(m&`P)dCGrlo%_p_xsApu~lOXPTfQZ)>6F`j2%*%UaxT0D`liZ zn!V0Wu+4oNs$mA3ObBrT%D{^<+6&*#;B8~wV(R5jl(Tj@p`UQ4qcjm;fHbB{1W>+R zF}jC7J6H8uw<-YEs_N|}2Jvwn8qF)|$lheG%0$pNqEzxZa}_&$LslbwFFY%w7q@j8 zOl#F0qLI!o`q*%odlG4U(MezHu#(Dh6bloR`Cd}w@PJ$yYfo6@Cey^U;a=|6g__S} z!gNQP3g@Ca*xt_$Skq8aAv?pzkan6~IW(*F_iSC&1jEj69fSDxdm-Knq$U%F#p|!W zBtDAxo*X?3AvvxcU{?L2XZVu1-PM+Y7ftMVN2}ok80H`~nL&@&d)rBMwdpoMiNJ$l z=+Fk6KQxFM2a*t&^F!KkT+Sd*PiLYMrAgvVtCn44r+@jb8guoF%@IS&h%IaY$iJT! z3p7_Ze>wBPAr(ZDL|#n5=amYuBY^UCDnctfC0%*a$Hlp}ZJk{Q<`o9uB&=+nhbfmw zCp?2LMjh69-z)2lZC0o_{sF}X3*EpFubV3Cs+r&ekjq3gRKkUVG=+;rU-TJgyGkyD zUV>izBSWPUnWEXHFkm}XAawP)R+oB6NCxDHKCBTnct#xOnf;v_1ax{ipabJAyo56w zM_gp+BTlR^`{S|mg8n?lw5H+T_ktO}WB;LYR`reAZ{Ri~%a^yea1$=PyuXuTK(DWzV_+Rnz^Z&%lIFM}o z2eh{QN4zBe|Lpv=?+QGz0B@0?0|M~$q=0Ez79meL<8*UFuhhuh=m z7~DS={>Pu56@Hg8h|fgX&*6LC6_0e10G5wilVBp{f4N+vI}Oj*=0aA4S0+i;uR`z6 z0L>o2>R+9He!Bx1B5p5^#lgQ)+9`hjQ{d6f$aUVR6zdK*5$J8CTn+;{1LSf%=a}U< zR8so87urSl8v|sAS|*DIQZY);E@b87*a>4Xo@nL6y$sF;ZlpLRF&69hC~rO0t&hZ{ zQzq}DLS*pmCaF$yoXF^_o0(`^X9%#K6_IZBrG=Q~X0X6wM`E+wbo8E(SNR?CPXYEc zX!)+PK0nq?Ie1B>`?l0GtpZJb0j#PX^g(e*|3xl~h}^>T1lFw~Es#_*y=I9%c=GwS zPw#L5YU>(_^&70ZciogEWPm=a?)TdKhnF~jtl=;iE@ZZEJQl$jSN#&59C-MXg`qwQ zeJ#Xe1LD0aqUabKNgwV0R0VC@J!)G~K6fi>ON}}(Z90gtrv{xN74Y+yUtfs8)?NqO z{-xn{aUJGoJB$d~ zE~yu$g@Xpq$?JmE_!^FH7t;ro_i?k==MY1HjdwvJZUFcr1yIjT{-UqkMf)o^7|t+h z>=Cw_Mw~mh9&xvq;3ZhR(?1~5AHac};CFfqRynuzi^n+QRd_T6!xI{HqFGK4sw(TM z2rK-fWn^e+>{>*)g54Dz^YnM~#K@Nb{VG-$o?^!pZEKH4wtpX*2`fjYaFg3`g_zPW zOs3L~R5o8+-5Jk-+g(ul6&TRmDfKU|wwl}G_I$63FH~M&of#eGR|3utuZw(FkB*5t z>5AtVbJM0+=~TeuV$=|##<1Sxj&vG&Ni5^^ot#IyVLjjRKoKGu=?QJDoi0E-Xp=-kr& zb~fCvn9o2Cb8LHPq^u%D$A7>cDJ2=1Yw0IHx6{;&exs(B9?usng0-Ue_=#PEVl9f$ z72_yG8{+zj?VSY$pRPtkYqU@H7*?ZTw|>BcN!Q#01dCPRhGj}Mt5QKnAumHOC*3`% zJLL&rAn#W_4Q$>>yEUl|KbI>6jy5g8*GKZ25!k!u{k;7|aB~c8`_gfODBnT6SarPp zWOOu+;DF6M15{7`MesUwi5XZ1rvQ(fyRXtMasGQ?^X3h_te?+ST|S?Bd|0~|q~Iz1%>a(H`kDwLcZ*Mt>7LGh@4Hvjrx(iQBj=gV!%VnunqFGUU6X-B=;>vgL$F zolA9s)Ki}@hjoK_W8NP1bn*6@DEGT3Sd8o3 zl0vF)g0|z^_488VnR;<+1j2-5M~dY^Z|ZA8#c{JiZXiXA7kC7XYQE5!C%TLKw^`-Z z)w!9jy@w1VxBhjE-!&iqDaa#Ox3nyPy1}l{ff8fJUD4G42$SLe2o&#K5>+XcJ032> zzdT$hfYUfJy1`IYedxX4qWNGFqLv_xM@0E(mJs_kt2nr?$(Cmtjn;(c*DmwhV(vG= zilbWl&Fb3c8NhNXWmt2HDnpx}d~oSvIX8!{ww3lr1k4jtsVM(pE1hjOL_|aOacUXL#lpJKh@GI&Y_VA5Vu|$XyikK- zgq^6%$+FG3(03ghsOLm;UoQAna1?2?2G)Jow@OpRMtF`x;L)3Z+`l^ zlC*e{V?%+uft`YL?h{3^eq`M$QW}j+BwxwONuSr`Dv-8F8e4?Fkn+n%j`nf&Oor)O zDOsDh&QIkZizp-7s%Zn}SWR&^-!VTRZb^*nIa$dx$?On(oliM?&$LFRXYLS$;lAP< zE~%zy`LrInJw74x)?@`Mh5?Cvi2@GBsw0rJkY`K1JT^_4DbYb8yMz1Wtpc1lI@wU^r>b(SRuZ;QcL`p|l7D4O6Mrsm&t&u+}amOUh92SZvmf(q~~qnfZ5Zn{uEz z0lF}6yYPu`cB#7xoxJ*21ss>Cs+n9?;bAhG5at!Rj1P2#u4KOq)N%v;8rKdDkVAH>r8aNY2y-9(m+FawpA;Ks4I>~aUx z4TZ%h=jKg!{yBRLrk<&9TM4|Fe>H~J?4XfTfff58@>%JO82|Az|LmB)BYjKM*Y~=W zuVTWeNr=1(1hA&gNPaZpk9fzJSksi)V;zvT*v8(V#3V{HL@> zDQ@yR*fP4-U!}!vAGKb(j|@hYOFQI}sRLfV>Uee;gT*Kx0t~Q(5Ctrxo#iQ&Z+M|N ze@!e0t5E}>w{X@bYiKf@z~P0WEX`HV1{!KwK*v%$ zn(Krtq@0uTl#_l~9y@s<18~}WD!QX59warHM73^vrfgK2%iX;(*N|tpk+rl|EZq_m z8RBrh!Sn62NM-3A4C($@Qvm!In0t)gp65|#x_jr$Dlq0uacK?U~| zieC(#_ks?FJ(&5q*?93ttF$4x5wSyyN>DlX5Dt(jhPM$kNh?(I$)lNGtG0qQvpn1| z#0fE?4lW1$NpQPWOo@Lt1ZcQ_4PTNUiPun-@;LbYonzjAu`R=5`S zXzw!&C+i*(qNu&F7{To)g7HtDump5rkzwGc^pBn9ieTzki%CHwtlO;ypmkpEjlLl`~4Lg%|V+ zD{9N2rr0vQGIG*8ad#YP*v*P}7}$at)Qtr>F666}w{pVe?6@A7Jy0&IAY^m~H@q1t zInK2Scr%oGzag)3HnT6Bi?{1ahhO|ECrg!H4ar=RRd;U1d%bjZn#2p4G4RMXF}SkX|7@u0x(eTlvO6Syi{j)&}a z#YqRCZ7w1HsT0&H#{@QH;Tm(*ILQ`W{LEWn1 zY`lXnZb_A}t^=A6wf_N?=M;I88q(<(I?0%QGJhXQ)_N@t?W^}Ko+h}kXin0p9^Wg{ zp;I6a97Nj`v2ZHKW;Y)`HjRJBah7rXTIP47x=iy(kz(Uby~K44L(H3P?8V@8BT1RH z1%}@=(fMamPLkYl%CPS|I@tg=OJUqvpAC#&?P1`USkOmS&DmQr^+=zsJlyB`6N9#+; zRA_cEU|4B(XZJo()@sqq; z6$S1vp3DwQ@wc1js(MvZRSQCY7X9IqarioddGc8&zt$<+CUBF^XhaRZ$7DeB=K0=$ zc3d$0{h0QaCqqzsk}DktWlzN~x}4kLkTZ89W$>B`?3PV5nECO96l}4TcMCQeu9PCt zOu$C`TiHGFZ?()=F6_+-F6E6S5QjoA14hYgU^|j4GCbcZMbcC$K>-L60Id!<9Y`ud zfu}U_4e%urC#fWyqS+NfQFH~r5Ucb3;;(|c@frORwOlbt`DBxY;>Z@RDr6hIqRQVh zI@ZPg<)t{rD=*)lYouM>U}Ogy(Dak}unS~Xd^ zD1Z^kQ0TB^DOCI8ol8w#jIGlKw#Yvqb(6^(jXzo6zlRe|HpIC8Uk1zhIau;KzpS`r zND{L_RQg_T07kMO#h9f$)!s*HA0NbxW^ADDxE;z{eZbDac*Vk{cUK&6!Gt<0GKsJ` zgeBN(h2`4lHPqAvU^-VMkja9Cq$Q4~h+it|RE2(cKR-9+&8jminA_V*v*=|}KB28v ziEP{0?|CV{YF>&}igiD=(z((w)N7OXXpFYfPL7lU=_dNw@m-9R0DWKF3Q(((nVq!^K?la1x*_2tP9cQKp z3jJ7`#1}iaBrh!49(V8sbqI-bH-ti{g9%?*^b3OcD53_Ub6E(bsAm@m+Hz>e+1Zd5 z$oWAAas!{Cu;Jk6IT7y06KaVLT!iP~C-ny4AS(AU<|t;a6u?r`LxC zvMunyrXt9>cF-fMcCT{xZTAATu27%nSa0YHb&364X7HVL0~gxo$j`XTH+^V1+(gAy zMsGa-xi!4Xy;b>;cdu}s3Af9R&iWdHqDfKesuz-vi6u3&9x3U0RtQfpYpTxX6z30n z|EUNXgI$+~@fR{Z3}MXCW%q2E-%!@Gg;5O0G7wqp`t=AG^y zAom0?r4hpKGU3PE8VP3^0){QDJEiXT?3I^P8kbB(BOQj@747&NkcQC#~W&r*VY10RM74700WAHAa;VBpQEjw%1d| z)Gx_?D`2k-g%c5FsGNrlBZH9q+aN%5Ox*k;c=z@S3&)~%!#NDAwfCis>#{pedX z7OwcU<>N)9BtAzsk7C7@7e21*uDP9<(5Jb48y$Uz$gTwU@W^gDTX#Y@f739I z@gsZcmVI>oMc;D@*}^OZyyD5{8Nu{b@7^$cHFRFF;Xo1;SMpg|n9P!lz4~cGEXmqi zE&BOc(rJu(>?R^fbSY?TL=s=@X}w8~NAOw%^~hohknAF=h*?XW)?=Dcf6?wa5{tWt z?%OjUf0NB{eFBas2y&Fqj|)}XGof4b$Jl_zIJwybS!H$c1|+CX=;AARd=@|VtQ-i; zm5!4yPtGpMrrhr<`3GcS08)9WKIesgLUIO!u{_26tS0zKpXZw!husNia%i2@P=}2* za_cS6uOQpXC@Hu9Q5t~auo?s&9uxpVpaAwea}zjh?A=KXpt76-6#R!qT@(*w4$A(} zsP$5ABt4k_ykQhjw365U<}ZS%08Q;0p8moBh;vk5hOfzEU4QzM(gr3xBdj~l4Up3| z0vvOH>UTZ?^*ff$s2Bfx&B&7l9JzCzh5ws$&{6-nK3LcMr?x!hPf!{7$*AR7@%dLc zzz+PMR0Hpa^Ro|`g7MI6cj)lgrUaliYGwiE)d~%25*D?3szYwm~(JXY{ zH8rX=O9NgjCZ=bZHGG#X7@C)@+2tbdvz^d{?nGm$R0yy288jofx*Q;>NOq-#qQW z$`;aIn5iH#VdX4wy4?o4I_xIe`-;1tyX0l+m7M*QO`@3p8G#*x5PX03@+K)L()PaF zglYhn4>8v<5K?MfwV)O7hXNtB0V)zIWbLFn4uQ$Et&u)@6!Wc<&4PNx;n1&WLidDq zQbNQJ{_blGgkH1tGe3x<>98@v|ARU@7A1`nE}?x@*7P`Q8Pv1U!^-ab`NU0% zJy@WX>m=|+kz&xoJF0`POAKTZ0%DjVRDx2J-uS)&rk)$g+bg5r`ObW3kw^Uekn_CW zBu=iE*NPwQ6;BY8J*(MYI+TQGe_kRYlba|?X-$n#&|iRi&!5G`WJIO<^!B?g;NnBH zRiSBt0wnjvcu0ruqela6PAypHTFxRt-`w3{cmKGLPAVn^1(x z@-`PkEZ|kT;3lKN5~s;BYdHDS0CK$G2i3xfkyGBoxba1VL|3StJ)L9*)Ij4&M&FNT zq!6G@hAL%4XQVYpONo!yg>uwBcsgDFOkjE9#pE?yhu7wg3!4gjN46X4PTeCUlorq3 zJJBY_%O)?D)1Wss3rIk|pBF;w^@kcAilHm8(;yMG-1)g*ApdTj7(uml z)MiI(9q+5sx`V)Uus5`S{5%5_Yd`%u{Ct99wq}!QCs!^J6GLk>ZMricRsHMieB)C1 zA#_EpJ?D#Szsbl@5B?@9!lS9uhsP32gOnJ4`pZ+Hu(F}#B|>l`*Kb1$IXw0#Am#aF zyYRPJxk)B=XAdik+?DylLpPc8h zB9oJjpMrut9>IP>uc86EH%4~KegaZ=_|??6>Oxc3gM0Eaf|uhXZR*u+=3(uvin`SF zStT2g-7-^Z7w}-VV7+f=dP)Z()IkN#Tgowe1Gmf9HU97*I285ks$J38aKp(kKWYD=>s;no+npyr21T=44y!wpnsDLgZP*} zh1D*aZ?X)ji-p@hd&dv?PFjv1TZ$e;(wX75F}v`iJk z8rCwi%$}ntF9b6KU6}jeZQ41Vg3!QhZfC^ej(`I z&j3sz-`}^=MS8%`1wcLIC1nFPtszq_z?in^`6ul#1iKRxByU{<#anxBoyMhD?IQs9 z3ms7+#hS_+)KxI*$q#fGyg+zMmiFyETTWLI5Gh%L@D`PhY@Lf+#17kov$~MS$h@1_ zxgU5wi{?dw_%J!&E4lj-y{BX!lQWR8RVC&}7GsMtJCj1DhTTW}r0;}W3YO^#?0jT7 z6dnTo<&vQ9il#}ba^= zJ1X*;Bjm*~c(8o!fa<%+#5_ODM0({GoM}zUqQ~5=NyX#(Voow{2v}=CQvF=z18GI~ zH^_6?dB~pjB%hFkF9yE7jn616)xTjE_{C14oA~&!-;a@e(U?%sVc=D=RQ)oGlLUc^ z7kIEVSS@PbOqh?gSY7+Z39%}1nNIahQP7eD=rN|pAUHZ7H;>b6z`)Ycu-C+XEt;M( zQTeJ%%8YJt{A0)4J=306(8P$=CiH!-750ndEZ8Z}*ivQ;nvE-6N>^d~QYRfbJI*h! z8gS6S>!6@em3-oirOy%srs@|5d~;oJR8$aFx9RUDR}4lT|A~PDZL*P!up~odtS?R5`d*<*96KA(Tx#@P{txWhzkGeB;e260D{WJTwI{i9P=GL3oj3l;j9LE1whtN3V6-4N0A;w2@U4s~axzTL{qA&z?s{n#~2Zn$QvsyK$z z+Rk=0Xi>UXJ>hP?WBkUPO#(3*G9wG99Nqs%61wV3lcFf#B?qcmj&YlN3Oc zVMXBk9%Rn<-HUTZuLu8LPDiSvqY09#_t@mYP>$Dj+D{+vXGGw1ql;K6#>}U!$@Qj{ z&?Q?gr!X^;t9oy#7OH)eV(Wz&wUrkDQ{6ED0}885G6!}W-P@LI@jT6d=c)1O&C(^o zj+T*jSgY0(wJz}*kXZMJqvO0{pb{P0RUn@(mGeDm)ybu6_z4-LSm1JkM}T`{YTt9f z!Cf&BtR{=EVJcEOntml~Bk7on|25FAvGiB4@mQ)F2Y0;iBGKewVN_P^XR0KYO=2ao zle`d(9x4SD-!bz01-%xfzYDr|LdG31giiN8I*#c)6E*YoC2`9F5}ufreq{Y3F!T8- z?g}X6w`G8dU+SAqxj5{|!VU#_83Bw#5g0tEAT9bLKo(6n0vjC~WB#PLvGk|94D8#R zfPX;gG`x{LmnYc>tL}e5B2Yc8(ZaVh24#Kdzhxn0P=CH#qKA)eJ@@|s{Q@4-%a%%x zv0G(NSvk*vHlW_zAgX5^0E`|TX{GdpA9rJYXYx3YS5PE5!LYEs)YR*cP=`R=3k3Gp z{m^LeHIMs%(6;h3jGRiuOpxW3e$ED9+hHgglP72OI@^+kUIr0dJ#Tu=Z3cTprd%gl zY4S9%UCws5KUL~p@Rj2y3!s&~Lki%2-^OSw02_Ww#7^q1M4|F+YSaI|;SK~Y0PrvY z5_r+y%Rw5!`NduCLaO`n3XyYnM*yziA1{GB!iVdoi(9`jM2=BDz$1$K^2M{+_VhHD z;UAES=-pr+b^7I#-644G&s?AP7e|x=;E3*S2-<&d2nm3Y$iM3%>H)flYO6k^W{&}$ zmT>1wia$4mng!sMll*f;ILZEVQCR)IBZA1EBSLiHpMLg?;Qvs-pZwwjnBmozRd=I4 zFw+CE>$KOKx(BO@$%}|hiD-)Fv{LNui-?srFPGfFwF566k>lq(G6|Sn>)~tU+b~*B zV-3=5czuV}7yxqO4`P&(FC7oCle5v+IeK7Ko0jtQE7PKvo&EtiwPZnoI62ny`Un4j zuq+b-&0q13C4cPVXFwH8o*Q3H7{>X(cwZEvRyJVM{aMmSq(?Zs9jeFlt_B`i?`(0j z6u&gfttG|JZq5?UQzoKhIW{}TZKmKCp6ST6)TxE38FU$pI3*J%3nR!S@o>kV8{-KR zO;&WPR09?McIcq>M>_^1W)yzZwm_A6}n>5u<_#<&+f8FH^VPKp9%CT9BP zrF=+2?;#~Z%+YJNl_zRAbO*?wcCWjoA>8e4-?B0LFO#`Q4ukma8xxRWJWXHJ-`+PX?u5$@i746Fy`^?Q7cnzQ{hAy8r9_sPAaruOq zi?>^m@eVOk3U^^RuA)YJ?M)#ACL%kT%J|Y5oT;L#!BJP_;;n&13z6CNFe=)2RyZwl!I@J^vx?`ERWqB84|NV3ifal*{EWS<-h85~Ix0A| zw?V6wC7^YuS*{EVPaX*eo(YA9%3R+^E%#kj`@fG2eP{JrJkH6Kumy>Duw)uiNVZsr z(QI5Z{rKLa^l3`wGUa#9?MN!MK2I1gS7>rK`y1noJ!lMUjb?Gu#IfO1fyoM>bN%_Q z*l=2L&M8#;H=8omx<|u;w(SbOu8W?|o5Yx@gnKi@T=rAY*o(>uJW<@@ z54I%7IxbxM?bhmeq^m$q8c5VT<@VO;TCA{n*N^NcmGRZ&tMU*o+0K1Cd0zh;l-|48^HzX(T5QydC*GB!cftsZTjaGu;g#1$uT66 zXf0He-@jPN@>@uI#yqV4{2p(BJMS%dkA!Xd;m)gaxZM|fh51-(adu0`O}iPx!oB_` z&4w4xHjwx4-N-I_uvn=LGx&5EkdsbxzSX1xx%)0q@04iBq+q7v*vV+MuaS!xs45?3hmy}DVB+-8x>sSs6Mk;ZvyP~>52r(Lf- z{5(M+grdxtKL;OLX;X6lWuvH1b`JmTcwNiNgKK}~8JMDC`pzXMQ2SOeEd8H$`O*L2 zkfNROQzid)1W7&ow={@7-5rx8uV9WO(G73(;=@hXbtt}!wj_{Cru&!b85?P0^>W36RE3(>qa2KSH+j}q#ELGZca7X9!Iioo^$H&dQmv#c#4O*ShU*W4% zeC0oeP{XCiD(_(*8H?Tmcpi^bMDyk7#Wvy#&m@H=^1K<{wXb2X|JR3S-KW-@dtipB zjTh%*V7W$D5RDG?RDTUPa%fBCCe>{}eUIhlazwfq(bA`}0g;=8SsAbGry`}%Q@B7L z%#TO*75x1>tE+z@F2|LJUhj$5s9tO0CcXW+evPXNG*5VlJTQgTnRU-t$BBHDPxKU< zn2)ox%I^4R&`H-XYCd}(>pS@(LU0{;N#@h{aBeR9njU9b9QJ9w4$!pF$SIhMob||C zxOMLY&aSwklR(*@2yh8$^0%XL148q|HY5%;lTS`r5%G!tfTri)?=?*V`BxEOW76br zVmPb6=R}-uFV-!vUeehHUVa`=io*N(Ahabye5JN9$1E?T=$n}&+7FhhW7c}~A@Oa? zyw!Uo$u9gN@Lep$PdI5#47qqRg=7^20+WuCwkPW{fbFtCQ)NNK-%E2>7 z08b>5c1+^e;BXP#je!?(3|QIq?8pr$P+gRd3qzDT%Ke6ZN4x~uLz|-G65b^-$ITK; z4zAi{Pf`WvCK6-{Xw4hNx_m*O<-qWyCRo!Iw3bg`t*upJrkaq^S#uXMVnQj>cxpjH zG+5ZrGy@19*ps?+FKHLd>OP_YiYup*IbZ(Rg-M78#HmzOC27gTtG3+IaGlUpILv63 zl0Hwzx5zIO()I0u#Ov{HN`}yQAi838637#HseD^csPigD6uBY2#_z&o@Ra+7iaaiF zq}UpV>x16TDuawq$aXD%>c>4kt~GO;Fw4G1fV(Ot3(bJ<|L%i7g+0xk+1nO;0Gs^= zF0`lRPM#j{$ZMwt$(7t*Jd6tcvpj8Z{GtEDG4}23wrvLS%a>eZg=T!DHck%B$%OU} z+S209FbK*wpRzvfXUAEze(>mPVG_2^8c&^u>nzbcmB@vW# zjC2?!y&{69B7zCo{6FSox|}TQYPF40Fq`*6)Xj8NAU)$2u6$SA4vOuUP_D&o(TJ zafu0BCA1nS_#N{+W4)+hu;IBG6(>?@>#H|;9n>+(MRXX(*B&)j$V_ojkTW&} zC@?Qp`c|U1a;nycjZr+%T}(A*jq%Ij>7mZOnqCaNjVwh+ zOEUx^`8_eAM*|$kR}=P{_f|LPCgiE*W*dI|qAFEYlw&g(;4NzaH&{gMzh^R0dI@3( zaTroK2)3;5h!k*o3bfY>@b76Gy=r*3>f_;{0`PYAU%ic3f`QfLlH8Q%G#|a6Co8sO z1I&7X{snJ8FtBpkMGk1h#EYs0qX`TN+&Zz^s2X~&-jjwaSIcR4sm6lqQGJQ< zwtbs*yP#9Po;iXKaB-4vK~qyLyB<4wOV0v*u&1P9JaY0)GUDDla-?Q#5iyp126=)+ z*z}RXc^nKg;pMWMP(jwWu-(ZyAXVmg(fIN~}Fs38q8j z!c0Ly!%GpRmk2^cCa-)?f$tBdMH(8`fg{ zlrH7{gwyya%!6+Bd7MT^MQxME>bz8#AbO|V7~ses+V)h`nV?9jIl8}_EC?>twblZ; z+()(}KK_PBK_9+X^THb(P2* z3+QEY^`lQW)z-4D$ki3yPvfALDzY1Z!rK|o*Z;Ec^4*sBUSi6c?qOfDyTg1|z&>LS z9Wkb3ownARk=@Zj_6tihnyl%XradR{swHyB<5V8WzJl?pJM~!fBzdN?N&v{MVRjY2 zXJfywq@aMcYL%>`-+7h4FOrhqyD+!)vnLAHjM7&|D>8lm$Tu00WMK7W0>Wn@>Xou) z(BzxndJ20j`*5Z*ARiloJDw@bmhJ>@IbvMO%4O-8)vCpYjz-_!M{3m&5wkzy|CQjw zCV>ONxOZPD_<5~=8ZD3M?hLX{q>^B^(k4KO{)p@*!<>O1>za8lHG=QjVt0GxGiE13)C6*7!o3Mp}lgjbq{ny_yo zm|Z4}iRxl#BVc2}>q$5>6W8H-+~ywI;;edCea4dqH17B8I+eP18m|#&z{MALaBTl6 zN6oxo_?lK|2jsldBG=UuD^B{G<3x%#{HZTbIiYfm{xKRzA$nctt!&qQEZcF){hZJ-zjHQNKybIDH zZo!=%8++BX@*_kqH*IHXn9WhpD0?~knpys1J?ElP7rzJzAVbuwa-dC&KBseL7&V(# zxX~Y;WG}i!=k^X*o)cQ0@nsB3UA|9K*z)!4iM?tS4M*P#v+uS>D5{Fue@T&{N% zfh;5bL?I;LOuMdW)fH7TPQnvZSNyU1`JU`01s!sy@4Z2h-7n3jsP8V_7#>oB`ZW|> z0UM-oWpJ&vYXU9qJ=uImMwZzC=#~}ga{NlyMp~>v^_-&nN<%zcy*D=f7P zs#mW&N+No8H|>3CeBFFX3wWDRYP*Lk)aDgf?8 z+OydS5u>c(s4)$E@OUU(90q3|xL^G*YfACosv~C14epE%0qLE1=m9Q^jg}{_n^DSJoNFvx5Zl1w&BrDjezLM*KB}Z(uE1#^N^zH{KQ1# zlZp$hUaz|m7MA?Dlh!y8Z((|u%g7tJ#X$7b;Rn_XhVOW2x2}1=U3_M=IAkHxZlquB zjs=zrn&Q(Iavn`}g}{i#55c+UzURJj2ES+Jm`^{x%4&(}@g}3$p3Zsw!*XbPmIh$G z6tGFQ#W@SaDb%?>BFCk)^4^7E9bc+D)|}LWUgXTS;LPM*m?o}7xDou$|6*+@GwO(f z3=C!W&t7pu0i~*+{Omw!?G{l`FJ4*AKKL02%|8E57)+WNJa%2TwIhlP8 zmy^WHe)ZZBUhSH8M{XQWJCAw%0r=d42WsVZrK6^2RW>sGbQ;&4?gRZS=Zn-gPkmOD zHjqQgxBF%U2}q>u-I*-&Ie~~uIj@12-M9hseTSN9aN(exVK^QX1pLc2P9ea7jlI|E zdtVwv3uM%&e4UPdA-q~tSXDb5)@;`OXU+Y0^gmym!Ce|>D04+sN`KKDg(#eD4D}He7$@Ehjn*CIe z=W$X#!)?d=eF~w%cxmX`m6lZbItdHq@N(*b@=zKZ4)skablEYGF~_slPFbp*xApiD z;Top1{27PZ*B}6B_{LZuM5-3rD`Rh4;X+yJ@Zrca&`l3dl-7`#3@)7rQHtpk)&p*> zAvk8H7)sg@V<03_jl60SwY8P4qrRd{)0p_V2Kp}w>EVAQ&wm>OEXh;r05Udf|4m5l z>+M}&tfGJEvhi{Oxqu!g%_#{S?0u*E<-eW5RP@xMf53T997_gnC&eRfu`z)kAj#rE>jX4ZGv+~ZRz?w z-D@lJX*y1<2TSTXO*4BKm$Oxz#3MU^=b~o=SCuu_)~=Pn*Dbr-OzV1AS}qo`IZ+4* z?1d~K^z!aQgG%963Rjp))bzI2Ot>Ji7~_?)${Dbguatews?qCq6O?d*l~HD@x!fm$ z&!JUbmmiyxQiE{BI2v4c67^I}(FQG>o73nJldNv%662L6wjRoSrN1O@zsY<-iv=&e z4qWHSi7!Id3}WrQuMJA>0;VEof7A=z=ra>DA%gz~$dB6cWg;zGI6r!@1p#eK2KV2} zC`YhrH9$~O^-__phu7q#VhdlBrDDvMY8IRLlj-BZv`m%Co__J{WZ_uKD-v+^g{rL~ z%V;E_&x{6_7Mt~c@Wk)Y$BJ}@Jm`y$=4Adz#}xiS){yA*%xiK_`frHVQ55p

    Z`Wc^0hoxcc~Vm`~_aJpg`!qWYuprRq|ky_pmtiZI1)H90-2=AhP@H z`TLEhg5SN&!^a5vB<6X2^J-rkKhnXTJ9Fao&Gml(?9JIvUZtezw)~nIaGm+QTXuXd zH7cS?sJBQr!2Uyw97gjXJE!+|csV~=hI21J=L_$|RnO#?AQbcUk?7#x%@e8q;y{N> ztLEsP;qkE9P0yj~Jw^AaVe5~*atG7?Sw$vETDcKPHXS>eUw-7l$YJpQAqRffoZSXx zzaFCj-L)XGd&O7QUUj+hN>?PPX6J06BIvnBfV8G_=Q3z+7)1tF(0oq*Z4!VsWnNJA}EOPe(*2% z8(zpjL&J!`P*?#l+(n6?EctD0j7c)4 z;1*{M#}>Rl1!A&|$4KNh6U=;_c6Ep{Ru=a4zWYBf%kZq_b-Au!P%)byqd`*v9{IU) zTNsk}8-H)Nb{vH5w_ySJ^UfOF&>MU3U3KH43v1V|>!FEAtQ}5k9H_(Tx)M<{m~u}H z*-)rk5Z1`7DpV&$#5-iZZ2{OrpqUDWln2%QX-O2Ef?@2<8l0H+jTcC1~7u<2$DTo84=X#`tXiYs(4HZ)TU2J$Jzb6q!DD z{GHCZylxVb^M}0G`4!d+8N12aU7R}Q)^W*eOivMU0GTFDoXsyFScY1{b_zr@JfL@) zXH-kAHWU4Fe@ag*2x@yaOLO`$(}f0c36o?hboBLQ%xm~{PqhZ;`~1R_SQ)*A3y_L?bqT#o|6*ON zuGuS?h?XX>2*LN9>|a0ZPtS-GOcuo$3wAWWsFv$u@VBWn51x7O6yJ|Q(KNl%ZYY9| z>XvnNj73_mH;kY^4ybDwyS)Z*t4m1=QD!v=*&B&H=_Mt{FB}MialP50Q$E(DV&0-4 zIN{C}7pi`t4m;NQ@!QyF`_XZX+tv5;{(G5m>hZS>O5`^MeyL7+&*8JBVBe~prWvps z`c+1p7RHPU$0pXy7iiOX#RN229u#h*q}d`-8YI!({8{ohkSMpJlC>2m=cUgOtO+#+GUdyt0pI&4>Uw?!1YcFI>*U#JMZ1* z>MPODl40QJmsx^xv15<@sHI4hq1eyTlcg1-qE$#JPjY-Rzb77`M5fQ?mb?bRLSgsS zz8R5ZvdwU}`a7xQFsdBm2i^2TPn00NSIL>~MYq>a2k}?hP7-99v9JU(=1bNuYXSC+ zDY$GrO2|hbtPC>@S%yiZi>_0On$ml2f6j(I>h46#8IN(Yg?|K&A~_ACHHQ|^Df{h zdW1kV$6nw-(Yn1at?)tjWP-y_`{@RPou&|YZie+o2g7ob7QC9n+ZlA!7w79inhUfE1i_cAwoBvJEw4ZBsW=8{`cD z&5L-Hjk$g8E;pbgG-{*qW~6NRgzv((i-{+_EP4Aq^6AU)3t$G>@O`B8>||XzCod{V zFAcsHgfk%4Cv~X1zQFFYUU`%EL%VVA=0cX2%)rRSwpubcU$aQ|vyYYL7T^oXA@M5F zxPB1$gI+~)5KFH!8F_FJl{ryV-)FS_UbJWRnYwT*X0TL67lJSQND#zcE;TYHZBG;W z0~6gW>==@h5<@v*g}E=SvwucbwWig1RGdARCzO+!-!hV`eiPjWdF6Wgnt_m5;y(bD zy_~k_huPU6U@39S6@#KXXd6r>H_lQRVjCiR;2M~z_g>PWU~X^fdcq<$FCDg2h88;f z_4?iK-&pliojY?ff|-U*=|h823w9sX%x$+iw47FuIde|MTF^=$73(-!I(T0=^a*pmrUJ!+-+{XA5|ljP{YHqPySwNJu5KEsTc>xT@@hlsVYMdBNnRpi{@Uwaj0u>% zh*D5u&f(*K1g$Xn46B|TD0oD}%s87VDPN*dkGw&%YLgI%G0rAA$bDm7o+~R5J%ezp zXmzsZ37Fv4_C7C;uF68s#&F2WJf3h|W~xF% zye~++gyVO_RiS^gb{w)Kg0YDu?sNrwZ>pi)Jm5~k$xnHb#EkXlXA&ipKRq^&G1K#^L=-kzKwz}U7B)B_ zyU=pbyWt1@<{tM4DuN&!6n9#iS_;qC809UE-@5BZTa#03jf5^Mtd?nD+Y?Hw2yrZC?)CS$!sdZ)H*Rs2uop-J|3m4RIu zD}U?nbT<|aBLVLVVjeN(i%i+an5YL`vbo>Qi)V4vK8!q!&-K*eGwod{;K8!`!B!un zS5s$CABt@Qi_4Z&TXN})Xe=T)K#UP{&2{1pWmEN=b%N{0o*nH6qashSTE4$OfPDmO zJ9SmZn|z;xIT#yq{XXbjm+46F#G!I_I@%ktMv73SmeCa>C3g1OJZQew1ZD55^`lI` zpAY!hxng>@DGh<6kj5-;eWuFl$sP=$Ek_SX%CR9S?b|9q?-c!Cv}!koO6i zrm3HGt);8r2QHNG z8U2~&a!;esHn}uFTe5?+tbaC+(vB~85?R>?Dmq`n+?TO}Xyd=-d{gWug=~g6S+Hx7Qj>m! zWZQ2i$Rf<5!9Iw0JLESAgK~xB(9hPJ&1ocYh|%IDU~}qft1w|{2igYO1}g%K-jUl0 z1x!|MG2|KU2A@qbLZk<_0`ScZVa~t!m>t8}WT8Cnp;#@s+X)$cn)0rxX6NLC#>lCi zg?1cIe&wjom1>Gs<4Eu{ot?9iYr$u20ArF8A;OBrHSl>hR9o-V?Z?EP&ZpX_Bc1MU z%sMB7<(jFOAqnAr@PkOMbH(yWSG^6;PhV%?yA8X}{GXW`^-s*~vQif&!;jTf*Co?E zHpd-3U!v-u`*zqpBRGAl9O2P7`C$0t4AuE(&U=ydnDc&rY6YigC0G<5RgLEf73ns? zS5#iRA6Lm@q`eB<2g21HT*vE!d|mzzr1Hc&2m45Ww!H<$oqQqJFYPZ;JKz}xH5!m7Il~I zFC0t)cIz+AUEhDRTykX*Q9O8>h-yOGAgdb*$K~{o8`^SiMMsn;^c_|C6Y5y69?nWF zljWEtmSl8HR3F33k@>^L>O}fA)t>ti_pRUdAB2C4?7#jPfPU347k5_1==AMk602^_ z*D=xHkAJwj3-p<1FlC^AbW6Ukm8-7DdXjiKPIa5*ie6QG5ryaCeyi7bMpQGtkeY#D zlj&>u3pub&UL&NVi^7uoi+cwJkF!$4gYLmAs-TdYc7Hc=m8Pf%GYoL#a(0vn~&c2_7 z{i-1LuO!9lDf5Q3h8j$({TEc2w_`N|{H$&Z*!_L|ph9Rzk?g0r`{LC2>gLD@OQ{T2O`8%k*f0cYOEaZ2-ZAZ`bm}lfKa35UGal+4 zw(!Jzl)08|hv&-S%9z$Ua4ljC3rf=>Kuk*YQV1ryL^E-n7i~A z@DpzYivmujuB1Z7`%Ze|>v7hzl3kVamU(e^jP8foFAoZht)8(a*4zCZ7k)l;V6R(}{76|QR%`ld$xI8U^&f_j_r62?ho}*m$N=BU6rv+cdBw+~ zso{yW(||Z*o|(_@l%Vq3Zb(0c5%hP^%t$Ys?Z&kSpsdsDFiQ2#o+U@u27v26FIGau z(34e^v}pw6Q|}~^1=|+88Q4sKP$T6A_tR~zPFlcC2-q^Da*8N55oJcFG&Wkqgzel4}OgP)e9 zEUHT60%8mVd&-rpux|P-49Zd8wYG#eB~La>Fk2wu6aWn{)c6CI`NJyTL! z_jDx&FZfpHMU1H#kJ=64FwXv5{rl$mpfbY4e&eJUUVjoY{5El;boHUuoK0SAL%}XJ z@&GIqS2wJ^d8>r>#9{e-aS`vjd?3GH55#ePXoT^})`&cA3{j03!*O|p?Nj=SA+_S> z<#WGT0}tEy9y4Fy(k{rY%N|ILnppe$j8qLi57HRxv|ViRy?<3{nwfkm%p7x!Vo{ea zuqhQyt9Uy^yPmGJ_c{i2AtH!L-qju|Q<0o4%KQ2sz;BS%U1r{wQBN{pppQ<@EHm=y z}Q@K`NTwt)iZ2;_TTNq4%yNznUTl3!0ipPup7drVL(e--ONauXuGcz)BJ;B%qAjf{J0XfCW=aSJG4Uxe#T;1xrK4>PrrydT?>_y@u6e=}8T@z*xu0C%Z*kjqPy=Z(`doIk9MJ;1@)nj5MTHrAA}7GfOAC zo$9{wSLnoph{))VmN-%xFsfxupCWI$aWd61A5x!a*~oMFawkAstfIiv=Laod?UM`aioe|A)`+WBQok*>;v z8l<<87msbhty*G{EWyZrJOae#IE#&66%i6yCtTO;zm7IZ-Tr4wf_$)F9xHxg|NLVt zBLm{lMCS|XMj{l~82O**|52q_r>bFImj(ZY93cnTZ0$0IvIu%#H+=;7(x2KFO)c)K zy+i7&Y^$+(1{k|WS%Aqy!;{}7$zB7k9`MeqN`7ni8P-U^&J#wW-;{w>=(@DUY zDdXPyZC^dMe{+=%UFj0T*G(9oYW&54-f%vz;Za@#<>dXuCdQm}i%o^NdnbHrNVMbX zFdA1Tj6rvX)0f-v=7^{gFp~8*0masl~%-k_=0A5}ldz?z#sEA4v0g63df zjv(Bvbe-=y4e1kFqYThO8Y33}09gl7fdPcTz#|4y#81W1N2Ed{IhmmumP)glL>fj2P2 ztnTR_27zpypKxIX@_z5Mg>Glm0%+*D#x0_olqlYhIyipPD6C{ar0R$BG-w=EuvhdsC?wVT%@u9Loi6#DA z_F-RU_`Lj#Z4WeF>&a}D)Wwuryo2?L^I;yyvrkL27-Q0%9UA$JD&dNK!`e4?&(r*>9x%*fnG@B=GT zC69(LB|(+5+1nZ7(BCLd-I9)q(XZb)n+Asl>h;>|YMy!{eIvgeEVagI6c^g}59{Lp z2pp!B`GrwOxuS#i4qyX7gs@TubLA6ah<+wka=Y9V=cnJ8Sal^o{X#BME8Y9$VetwwVr9NzoyTu_BYZ6wWNqH7CG=>6UfQ} za3w!s{4*|wN`w41b4qi*eUBVqrpzLxzbb1w<1v_KISU`?cM1xu6s3s?{ldKU{KPG0 z-ODf4npXFwF)E=F+-N-5uITQ}56D2{-~s(TMpekf!}Zx<17e3J=)Cqf3VV#~Sc-B( zm_x{tR&p=guAA&*R@xSB;J8R3*P`T?oC8aXW3zh2&$7BngABd)FI=IB+v#WOnTGtY zEvqWa!*-*ilbBZ~HG8}4-5C{Z5~9Ethg$Wv!J|%9Y1~^ejP9?U`CQ%WglB!6-61-0 zA|uF;-dMn1YtlwjQqt!zslVm=2P^9mX4q_^&k7yi>f_~uUvVvtxsqb>8PJLYgHN@s zH77c{` zEOkD7p0geOj6-TamM5Ra@`;(M7)=JrWgJ3u^PEz@m^yb{oouI#>u=FoAZ?+V{02M7 zjkUS7pdo>(=2h^qrm{Wn$Y&P$BkZfX%bHEH|2{Wy!>_yFHk%biKbKiL`Y4y>-3zlw zU{-{rfjplJ=~?>DyZW{c@x8(so)|b}<&}Tv#JpnByS92_s^m9xhleKpDM=!To?>y8 zv#H)cj)R?$w^@Hoe;1Ra_sb*-{VbcFape4^2^KU1mAu;L?QZ zCr>FMEefh{1*A0>3B_eq;i>AQ>%NLD<~c%k{Uqvx!= zVzMHKDLynNARv&m4?V7w)hB!2)73S=Z1uqs(>oO_QCue3?qZ>WL53GPI>OPf34WAb zmycR-nF7VClI5Ob30xoKF+=fy9nr@LA>h$=;It)S?a>+XlW($-;XFQUy))fH_n;EKl{Uh8KD>8N?hDQjRn2p7GQ`51zx zLOFi8Q8sAnZI7yn<0xTDlJn0O$zU-wDgeB{rH^wvHmmtUTlk^4JQcw;)vZF6xdbsn z+tOZ&%Tf_|H=PuYLOeXC40g{NGlp zB;xzaHXLKs8*JBaR|)Q$#M0S+XJV6cULwk9tDe3em*^$!nWYD|)+&YTcivds&AF^&h!vHJhJkJAPiI77XcQIyea3^2k+k)GI zlLe)|!7oJ$Q4>!AAzQ(ronu1F!B;F*Z@L5WoG++KoQ|18D*UlijfT$!tB;X|pY1he z!B*}AGMcW+69x$08O9e=Rt+hZuOA`e=}XL^9HrQ;Q@AAo~qID0pr7|@g6 zd-OH?^y_18-k#5`<=ATslO=ZIKU3!VDFeYk>-IVB8}N4V*>Te|5-Lt7FFYvKpP-sz z@FUiEiD~PZP1sO3g?v`QEQNJi6yV}st@Gaiq4>N@{cTtujqfPuH!rF8gD?HE9Av{L zLgNXJ=aL`WjLFy4oG9VL1)>+c%}jd(WR1<|xDYOU$!aS7 zm{w;!HYF?jRQ<~U#${*eIjRr^C=)tp)hkkH`rwEK5!hbs-_4UtUCl00x=ErLzX?&^ z>CZ-lHgGR_HYf7dD-inzC9~Fa?nyUSYztR3&;dVadFFEUnU zq-s+Y;IN~i?fiv)B&1`yKku^rPlMRm$_re9%U=mbjg3to7&5<(voi4mrtsPXrs(Ytg#Bq~w5e_P=1(ZVK%tuHpMVtwzN9+i-%K;w$IEMq0!?9Q`0-D6yZ zo^C3;uaP;VQ#ll|o%r0L8D#cv*3;mi)5=*1DN^x@;(wxFXO9c2Mtm;?;{9M;DBUp6 z$q2m^NprEy(ld;w=Gd{J$H|_V9qyPodyW>T!09a5Xlc>Z-tou)8>L(ML`n$~cI|vp zP0dgIhedQ3lv#`o-X3=gQgWL?q{9j>jG8+cNGnOAx9wC&=$_w=gmdQJ!h`?=rw#T7dBdP=o0nj~E@$YEvEpF+KI zmKWtjS6@lWZtiKQd?zn`+apIlf?776TP`XeGwPixo?apmLGavYmP~06#tC zk3o?_ac7BIJ&-u6L3t07Q5PU!?DZdjwWtp=L{oz|CIK~@oGR9f{U>(k83sEX1?n z|HFCnViMJ8JxCAYAtBfzb0FvKK_d`P52`>wl&hOotHzC&0HTwzD3i!k85yo?jw4Ay z>LM`H!KJJ4`q8eltb;;nHxzbpIl92Uh1y@sI&cT7}3JmoEkS6sa zGz7w&*feoe$>{PX;E8TaoG-rKObCEgI&r>fIOBcJH7m4Y??qeq0bx1|3mgvyAETnj z#95558_z!zJ@M{hcGVCAnm>q;u4Lv}ADOk}mT`?c|AT%Xg*%uIQgUXI>f>r=9;?m4Km(f}%7X~<`Iq~L5LK#K#!i|ZKG`YD#O9ij|aizflxY}C^y ztJPHN|H1^>MZSSh#Uh+1<+*4B@=R%Bp+tK42d+{Ne7O&6a4wO!9Vk0sRNZ-WxarTiNws3v zS_Imhb%xM>(MPec#Ul?$^R$i$9psRCIfjODZRaxd4r6TsM-j6uHbJ763Z$xGzM#K)v1dBF) zy61&GN9}hfDI$qX7yx`HUQfX_X4x$y~2vU}E)UrNZ;@6uw zO0B`sH7x~a1p$!oOX_V)w;9%#>RR4r7-;efmHPyjRVAk=#N(G3iY#@BwE#7F8>G(w zV`#8({IVSdE#7i3UOqLqa4=z4pOOaaYJo*QobD5RquF!q78y>Y@j71Zv0&lTe9qyW zG!M#BX~m~YCy3iA+h5ruQzA2yrpk@-IO@JPMb+IIeltQUAv;tYz|#KRH^q!ta3L^ZTs;2cErs*#GuyU$M-KsUNGKZ6#S~^e8aT$n6jfT3BKuLP z@7OBpr$zEhl1R4<3R0$N$&C!OkK2~6n))LfsGgA=_zq`zo=O1f@Zmx`klo@aACfV~ z+q9+g#{-)JB2%b_KT<_vQrsZtmr&S6j{A%r*SBbCpoB!j_%a*3&(-VVPva!R>tew0 zI_*Wr*Lkp^uF7+H!2${Z&F*xevvj7nQx1);AG*`sbUvN;OV}bs6__{MG|TZzoJojD z;A)T@gX|dBtls+YP!-Blii29){otCDKc3%6g`btV%2ldP?dj7vjSt=*)Ro*5VHey#6Go%tk$nmA)<#=SDVQYwlO|8Bd zQpuNEkp)LbbgC09F>r9fVdba4aW1o5@H z3{vCBf}r?0axx*l1lrW(D8o`3VroA;~``)pZomD`#(wu(L9>k)R2o zx`^HlO8N{)IB^K99r-Ab5F~YB9H7N!EodED)RbJZ$8^+5*`C4Z%88PI*8(fEI>{fX z!zs5dcF8_uI#8#Z*z3*7%SuK+rCowMaIU9_Outm9R)7)rgpMhiqD+)ypebT&XA|=; z-AcA^&c@#e=wb8(ggCpj-9r_s(deJr50%<~GM$bcp4q<$rX7QDR`Hr^m+9ev*NAOe zE=o%Q*O#MGE|y7x{h*pr`7R?zcO&i6;Xy8m=P7Z{o{#$V5(u}b2g*db5SC+>$lP!u zG8p{~H;;LItrecOxWZvG8SGMWt}Hrw+n@fBl%#2*^_?>THZNG{XQ&3sgcc+eAAnt% z%~fnQ#$GgZO34aW77OKK=X@D4jCm32k5y~RJX$55mpNmC`Cw959EEWv!)TpnJhA6S zEqZngkAf7DE>|qN;hm6`F(a<&Kkz;QS)0(v=M>bf(tb8j^tbjqzO}OA;2^W--5lZ6 zHt$FTld-$qRM=o*e87QprOMq%lRBRyD!-=YZ=roNshE3=Ucn5nq512A&D9ooeS}sL zl5{T5#D3y*i~MjRx+$cPtssn^fxSMV#WTPuf?ZQgDz4J`iPF^O>$ebVDDx(CPtmom zoBMP~LkfE(tRdS_Q~YvLoaHGxrPNg=TAf`SzZe>>mhq{gTd*DmTHlU`63$5?%7(Y`JLN#s);3WKaOC!d~B=7B(gj zsy{WS@elYyV*y(3P6YK-qHkZUgDsfgDraW+kv~u^2=AFt^o!E)%?*N>DU@V{bg9{a z!7-aO9F+!K9;&#qz%BaAf>QXm$P&$rtlG)v@)L~cO0f!BuZJ@N4(enI-N=dus%T)*p<<3Y5RUvmuY!<{0KBuTA%(AcVXHP-0L8al7hI2@JfRftKflkt5B#FE+F4 zLw44zxNF|1%T@f1RYyOoDdq4O4YdjVt<1QS>P$7(lhX&F;i%q~iM1-+?&hZ(U@Vx; zxp+Zr=|a#qv)Qp&3f*q?R&$Rl^lv6iou=M|6+_ zK5b)=oLFhWA?Kp1_6+w=-B;IQ{e}Z~3C1xKJj@V^Kfd4$ytqpFcNW}eU*X@Yv{V#7 zWQ@}@rsnMCs2#fMTN7R6?1Yx-XAO1StuCo6dE0G3iwiXDwTv53R_1D&U+JrfElGLq zGwo$;Gw)-QubIa3@yeMhg<;|R>!DnGa${-|m@p{~jvx9q?%t1LLI9JKvT-c>*4!xzuLpR9VqE#iZQ)a7WZyl%SY{gf*4 zcM`+Te@MSp?DPbcfY-=Fd=C#K=F^C$3U-ItayKSM%5}AzT^v+c(Du(o!0?c626cW7 z28hTs9&R5GNkJPKY+I4JAeOgzU6*H4JCnSsSuteq(X-4}J zxvc9Ad5{7m=i%c+Lm?>SlECe=&WkIwzDy4Dhon)-@7bSuEs;ZhqeJgblrvX;r|7h< zEz?Z=2SALl>t7$W%`-I}{Rn4AbanE;@3|LpChI?&1NEOqD+hAH?*~TTyyc~W9BYc> z1mU|63pv8N(yLf<6^+9l2fk5`?Oq>sSXUYq-ST@TpYz~TNzhJMH6-Vg85FAR)bSVPN>NeRqT zPj~zcee}xrU6vf9!`6oeZ{%*t{bA;uq{ww!zNa;hTN{0=7&GMo!5ATS3jU=b``2e> zDIWjc*{^~M-X9g&_ac)tlwKwL-Y9>Z0=9MCou?MuGmd6|3R9OLl)0Owv%5=u*Ftx- z&$)T=#ev!$xiBhN4544$oUm#mF+!2f5D;2z-+XQfQ=UNJu13U@7f zOn;%{(wik^EAzDP(#ON|8No*5PIJ?ePS_wvWqC-_5wW#VsI`0;t7Pb*$rw=??C84^ zrG8r3ja&Fy%=Jz>-=N#FZI&Z#--KHqzEX-HUQB48qn@H+Q$*~NQhP0zCG1|&KtpP) zPd9u`z?>+nA5>|OFw~D3ELt4-Fcsq$+CNvmuwZAo&psV3d~GIRWF<>QLewaCU%InJ zOaWz3a_A&Zb}5KS$WoS9bMLby8G@~?MGs~8{&FuXd@0-#i$T_L_s|EkByN6TWtz)* z7;X;bdht3mG$inQO;NIDPTw|zA(?VXRZ)QclIAB52Shy1FamU5S~{u%SGIXuT~6d3 z9-03)^93*p0Rqu-RLVQqd%U4dj5N*oiBx$H(`eX~8=I%X>WyyLQ# z*d&61FbP*Qm5+Vi7c2a{p~3VKvX{1>Wh66m9;P?ZB?sH`8Nmj?=9_nu(l%&B_h92m z1GuB!zvWfMKoGHcOnSkh;(eJhC@hlUvH4%IjiP6WEOnt?^5qKcis0beP{jUX(JU+7 zi;LNoG?Gtc#zTGEaPSuH+8W|8Zm6DO>?{ZmB~e}ZseDOd_8(_{d%!k~RVMY&sK~yB zSTwFu5mJ}oGFS9Fx;Y%3USoFrg~e>7G{e=~vt&COLExHmfqG(gK|bNqtM4VRg3314 zpG<7c(BqKei{jx0B5&)6hXko?nQ^%;eynJ4S^vP<$3%O$j7fG^2MM%jnEL&hyiPz1 z@=G~NjNK?J6l|c2>Y3v-+R-nq)eXX!QR=RK>Af8<$xfnOht#F@X{v%75SmY}bIUaQx@j{m=j;MS)I0+NP=Tf?%3sri|xyrek z6zHstQCU3~5s4MogTEnQwgf}=CUId>1f4fn7x%5T(NX9ivHqvfWFUo7KpepBO@bZf z?K6^v`0TWrX@H-;+Fa~A?*Mly(VF^oU`!an1we8OC6vLaY|ObyWx%VReM(x~yJ5dx z+L-k%Q0GYjg^}^Hil#G$rxUqvAWV^Yk0XoK9Y)y~&z@;^_#A&q2cv&^r~ zfQ1om`(eRoU+Zg~MU|p~+j1cKt4G!OQLKY{k1uJe?xn1?`3^?<8I1Yr5%`5Me>g|J zayKag&^-W+n$m_?YG$M7yrLYCT~`p|A6Gdntx-43tQ}4eJ0uO)2LZ_ltEv_jH9t%v zX}c|&8ebBV?>UAps%QE(m*)w#$kX_axeTX0D1*OAT@doJCK$gKuIgz5UxWxOHMrO{ z9=_vU)72%`jm;qrA}utUIYLDBB%|eXHs6~+>CZq5g4_=e54HAgD8`@kxEJ7W#Fr$H zar5`PLdU16ED!n$fphapsq_kmmYdEEP0M}QoOa`$IW_^a??bM-Rv$d47HR`ZDxzrw zItK4p(-+~kwi`oLpV->Q^d*@;$!4*|Yg1d=oMQI@UmYssB3YM0Md|OyX zlm;;lGiA)?wA5a^W-?zH0N_F2fbBzi)8{`V?xIUe5r-sML~e)UghD9O=uvXMy&Jt*Y8cRFzL( zgZkf*{mQ(SkK0&s%x0msqmkuzydY&zgZTQdBlUf9W1;ckfnNJ=VfRI)b$3+S0luH) z801jb7xj%hK!u!;B?gy7?f}x&fe0ICfXw8v(r9*4fQ%!KB9%!B(ouH9Myy$adfazqloCGMYGPu#NB(Sou#&Pm^_O z;{bG7)e}oWrH|4?FyNrIv$(!=%@aL{@Uhh({?Km5OG%>YY=2igphrbvR6cl9l0ry3 zAkQa-2ZwQ`Y?<=M^a6XwYWT;Ax;`V#5V6fdy`M-N(^CmXdzN-D8gP0F&u9{lMxlzD zi+otqZ2Y@y&^A+;{Ki^#GwfG%%MQ#vY0GnKc(Hz~uBkmDs9-ZotiqS4s5(^=xG6=-{KpbqQrsA`;~9`YE$?nY zE>};_c-b=@lTXWx_p^}4;3&rRBQ8=G710custD+?mX}_?ELc&XX4A80Q2HA}5I&c> zg_e>s{`A0+NMZ}Gw zI+tF6nuS%!4x)AUuY}dhQvWpHJx4l3Qvo&^>Wl&xwoM!<({(HdURotwm0atlkz~^C zjsEz;yMto|A^dfy-BF?bc`|Xciqv6e^(ncFwomcWn_+Uuh*!MasLkmwA0Zjbt>dRI zpJ78!^?|5`vX`Qe``{TX^2JgU2L)3qOO$-L+(AE2zagyws;Hbck#1SoX5Y=36i+3m1mxRC?C$K)ZwgEvu-@xPt}>UM zCfvMW_{Z#=9-&2u`xVBg)0Gh%Wz%PUCDav-*uT0M6PR$i;v&A|`RNI5f@ zc+E)5)?|t650DoU`aZ^*HxaeXW70D7@0$yD)clBnz7_V!Bsci3xZyN4pd9mL6B54l zWYfD?u}O$pkg0qy)>J@H;}F5-bHhe-Z|9K|);L@EHQy=$wpHhjUVDG%D+}gCIqm?R z^y_yJmm6GZY0i_iKn$CAUIAojdH)um%+ggoJ6nQ)X_CQ3BY1wQX59}mlV&uY-nII& zm1y5&5YFKoR)FdCz_^C6R}Vjx&%MV&zJaq92A4@UMoW_l=>ax1P7GJYoB-1LM><(* zp_cY}&pr^6%ZxTZ$;#**l8RJs^e*>ZMpNz#JZ~MNG=^30o`_hRg*@c19W!8w!^~mY zEEVdC>$99B{la)=_KX=UePgrWZ(i3uE4q2YG<^0nfXSJPvzvIyz*eVsagUIq)$MGaXDp-7CjJD5Om{Ib*Fi#WLkIhAvbI_sUc1BS8g3Dn zE=f%>KP_DDRPQqU=J7Ay-pS5)9mvK^RG}Tcgo(9UE}y^;wOpZa;d<`$4i|!&Jp%+| zZl2@R2zJrJ7v)#5ero8!pL>(mgqhAj$WqE`NA)4eD~T=vsiqrw%J zEK%EZU8);}lDhhWtQmtaf{4gXd0v@A>zsZO^~LW@6ET-N=!yQAkhs*JRhF5Dquk-C zTq!$N5lCZsBH4K4M7l9J8>b*{+g)??yj_Y~kS-dX>NnTKVZPLUK$=UcSLT!}pf~UG ztfs2e&X=8@%q&aIcsA9^8Rc&f5Sjg^obvu1QLf~Ok-9Rc#&}vkwVJ?STSgv~KAdzS zUlq!8xsFq`L6k2T$q@njBN`RDC`JBU-z5A#K3x$1mJH1kPyHFDv&a&(b&Sc}66^WyG3f-84>! z)cQQnepwUw$`;3DOYt*iRAAvx?)~t!i*KJ}J+q2hFxdj%)nUMNjs3W^{?@3UI)SHL zPr6QBOi9~m&m-Z4+++%xt9Y^<_$%Ah8;cL_eOL;ANS%0HGXJv)=m&}v_o<8tVp{~4 zET^gJ%fA>|@lsHH(9(SEtSA_>O;10au1gO;vVPfrQK$4wx50WJ%Smy$?^)u3qkQDm zk)c~s?a%Hosp~EB*>kW}wOp4Ym(Ap(Vq_o7`fo42EceMTZf;<@%{Tt%IT^a&1RC}j zxR>LD_oc>u#sCzQ86$Y_eZNMhOD*8JnK&FIfP!5<5>pp{Kp~;H;X>;9KQl9H%1uqO zF4m2lEOpOHPUicr7-!spAN6N~=HJSHWu!}0v5jS3QyBpbF8#{c-7qR1uWVhLwwYyG zsZuFHqwSJb>9^{9jykN$7oSGBC-c$Tili7*?+>!qd}{1Tb-g!YDRWN;eD1fsSiWr# zcwZ@?CZ+b|K>l3fQ-G>UK)=79odlE}3?0;D*fn})^DXeR_Uo$&PF-M26iKJqB)@Im zN&A}Sfg?V;BwA%}xvYV8RlI7mIr2m;1u-LR_x8@%3j^6wH)Dmnx|K_vGiHMV?r@su z-5Cm!deU)ekS)ng&41vYRyXfZAxmE#ca)T&%z#9`Ut!`^yvKC@t~H@TN9QKfsNGOQ zW=V7FW5#E}{XzpH^wbAA3n%+OBeSV?De9={xVwEc|@9ilB z1%BnHw>t6qxiNq^&YMD?A2eV*@U=8zX9S1JuBhUB?yQYXw!q1BpH&S8I#8N|8L5P7 zG|~g6RjA5J+)dK)z90$}UF6`6CRw!oCr#_`ywEEeM>Cel2dunp#Lx{(Yz)%?FnAnR zo-Ke`&o{8IVanW-tzl+MHeCgPe9ZMEQ5}|;)*U2JJx^cuXsOaLTX_m>HJ@!wimyI0 ztXE1{=*D(^LD3mlcmltjl;u%DPzZaQxBV;?+hRqm4LQrltmSb7a^djj(aoHkpo)E~ zk?Kw_YJKcm$I}fomt(W2WabBKp-NMGt5p3e1~bdv`2LeLKHtk-0D$sZ?l@=^*%Prh zwO7hsjBgAPMR0caPcd}br`j&j?Z`|+ENdhXqj7OoC0gy!!UN;WMOme@M zDcuAO-iUmAza(b$BMaRUT3&nKkG6BAI{J3BwpuLTWAX|t&9(14S+X2iQ;YVpXbqM6 zg$)=O7;iCdh1V;*$dU7*jf+K2E&H7W#lW`_K^r~aWT)v8q`=CMyXvvw*%Bf2Xdk~%M3>$!r8?=`# zSJ7d5^5AmrYh&c)o&$B&!EYoT-PEBfGWNO#B|b*_EAFGCB@bl!BRFErNCJd3drJvR zaw#(yHDs7;t4LvC!{&h)YQ{;Vt7{Yy!eqIe5sUn}g!j)&oH#2VSu?yXxe;`!IOqF| zxLZhXFLAq+)xcIEVBb2VmQ%~UDh@-|y>C%O8N}YNgOvDk-1@uv=w|xq&1e(~@w!uK zln=cPOr_JN{%#D1CZs(FK~0`&_s>+p44V#9;zw)ytc8 z?Rbs`2q}}GYljo^m@R&N)Puj)FS{Z8OMHQ!raVAJW-8~c&%K~zij};i!bb`;CO1DE z;?WN*jvMBGE7mpd4hk*6dc05|J(5M<|-%vp4*QQKna-*SVOfMwN{uo$J5E zpMApf_EK2SY4*SdPRohOK|bH~chsR3szo)!#QjpS(!yMc{E8(^g^k6u3x;=OPJ&Q& z*KP>6q`p()B-IVv_=a71>>rVs92Yu;z`u~K!FonA*I~}8^6sBUZX+tjp3iYpa;TC^jJ(Qx7qk11V z*4Y~>fEUQR1)>agx5@=aZkHN}<=oC&IkdY|~#8!QbI&ZS<8pBZ|i{=z-jTh>C9KER*2)2OlgT!;(&~#t#|T!qpg8kfKEjWUK&w zQAz)qJd*3Cee>1xN�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

    I-=Q+xm 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 fj><2t6-+ImY%u&!2^!A34dKeGPa- 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%0DIk#Db-~UG+{4+^oN$5YkFDT;o|L=3nC87V+ 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

    ?5Uw8=%zBmPfYApXv2Bhp4f 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 z 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 literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/HouseCeiling.png b/examples/starting-expanded-3d-house-horror/assets/HouseCeiling.png new file mode 100644 index 0000000000000000000000000000000000000000..963ef46e3c98d40c0919a5f38bbfb0ab56d65930 GIT binary patch literal 23251 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

    R%IEE_;Sp%#HrD$LPlg{Yw=g$VrHQTshwx|;7a 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

    )7g=n{4^S^6X?!T{t?R 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

    mhrs3&5tF4`TI#`@VmD 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 Z{}1m!jIn4bthWFF002ovPDHLkV1kLd(69gi literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/HouseRoof.png b/examples/starting-expanded-3d-house-horror/assets/HouseRoof.png new file mode 100644 index 0000000000000000000000000000000000000000..f09879fb8748fd04d68e18ee3d353a897f62622a GIT binary patch literal 170763 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⁡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 z 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

    `t`1KQ>j^z)aW7t05u-sie?(Q7%nzj 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%0DEqixl`VtdJSJKV&$owNTMVlHPA3k>pgAVa^D< z86RhcNGx2>#M4!$M~4&tX@HJY6}nY(YCY0^iy9S09pkMPDv>k&$v+Qov^pnIYm3U7 zui7SsOXdt-T9{y*Z_MPH!6@3W2?R@mNLD9CvcY?h5A#rveN2t8)2_N3_0_jZ#J^wV zT?2fpSZ$?XKD2$xL%xk}08|kHfCG7IJV~n>oK+Jr!7(cek^2u*nqmuwr5qd;W?&{Q zk4ceyELf!lheUJL#*ByGR${Zjl>G}QxnaWcet%NveJPxWT@!nVAwD~TMd z;+r@W848L^L7y4H13)8?fbxlb;*l^QQr8;^NTO#DFJT>}`6mLQe) z@s98Y69>Rz(q#A;x7KwH5l5DRDgi70^*Z@35|9yaZSZna)*o?seLn9oCZ2zyvB2dO zPY=&O>!FE59q&cN@srgMdd@jU=!5o-g>QfU^z1hPmXz%AqER-o1&y<3=AWE7do_vJ z64*gKhkw7WuUR{eejGhDU%_1l!)l56b$!tfKt5}>j^pUP5oe>b#Tdx(zeOp&p;eaa zO7P5+T%?(2utwi(t89U4zCj`HHq$IA83qYX%RRUl*L7h#i!c~TB4gsdNe$!mCPk?is5PG#n6U6wdCQyNVD~Ab1RSZiXGhyNpV8V8H{a8 zp%vwpW?NBDYkt9cC@)y^1eUwx$*u#4w|E(V$RaVE*frr}tXFp>NE*aywTh=#>DoF3 z2t2(azi71l=B?BIUAB)jjTJklitwBX2;Tb#v9<6QSjC?W zf_gb(0XVS$#4FcZ=TU^c^jlS_&Rfr*U+Ob_v23f6*c};HJuQbsuyC3kgb%&L`$CK&61&t9aZ}*_SKwY{ W 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%0D>ECQQgu_C7sA51l+IJn3#EWN z30$4IB3kkuc^#V!F^>kf^E{DIt;YZQUT32pFX`;XtIGuziO6w`>(c-CfB*Ae-)B

    nI_q6u~%8DBDR09iqUHa#H{`sEYm-odvXnKGg9)SUTr|amQ$@9sgx#!kO zWgX_==pkgP#M4JeLmhwb0aSz_0e~32h2coMIU9Uiu6Y{5~;UoxXh}==lbWb_m9ymK=E+-shLjybk3=F&X7@z7S+^;qlJW;Us|^**mF*s zpBd4KTEZjkc7QIe?1x7!^ti}#8-bp~)tp8T(@eUrxx{9f-k6eT-X39UP$K{o;kxz^ zP{LhYlkD!!;N4h6+p4O(2=XmG8haszSs@WIFJ-*{*VNJ7Fjz%LDVeP;NNrytDtEu1 z9c7fiq)>Si)BF84q61a!oNkwu1_v@`uhImh@3q!-oh&l?VDZ>kbSTH`MPP8I_!8Cq z>&O>{I&h}1A30(5ECUhD^g85g5%%GkcF%4XS29m+& zSsa6-Q)~ZxFE#q(C8G)S6~cU~{nx+V|N3>#rPW$lRpb?HP*w0AQNkWW;c2C8Yp&~k zE)+Xs_;J4$1rsL!8NK)8*lL#Ei@TT-?^o6CdHFI*OUvMTcco@((rBHCF*)VQi=pEp z2`W>VPbCDpo&S4I@<-X2xs8@hlB&T9$HKzR#5mv$@Qaw);a92O(Jb5-vsflpE?rPG zt+m)<12K9Ihj;1@yS@%p7qB8oQ2*cmIA5LrkH7yM-2(td@7L0Q{CWO*PiFr5dX3)k z4!DR*7+tSVYvxkb%dTcEHlyCPC_<1TRH{E&Z!v_S%vI+Pp-QPUvsAez+il23iS@Ti z#}2S?O&}_8ZO99#&PlVqtw5o=&XQeKZT*Ie`J^>ZtN6`MPl67Fxpw*^zTcOrHW_B5 zM#Ltp-`D&;*EKQjd_w0x5zs_~8ZSSb(?9GdJ(^33>Mvs5b)&ZP=2j=#sfGVZyL$&pI0X4ufNf-&? z$lf%3Z7rj2)wJ|>+Z<5%rjC_fs$9$mmXXxt305Y1A(s#1EASin&ZOe2vYu4+*Y`E& z`g$F)izYRDU;67kQG2%Dh?4DUb1uKHO>#<3d;Q=%)J@27hU8}4m%uTq7g#+{3Y4Vi zk;oqV8>&lb+l!n8sRmDJqeQL+6lTdn7ecOY1lHd@^G=a(EKHJat!6dMpI0tlaqFt`b zS4^uJQEx8vT&|kr*K5@4FJr{(kraHs8+kS7)LuyH0y(E2!_?+=>6}12;7N(d9V~7f z^XrpP&+{@ONP||?sv@2XRivjOKD%a6_7KtG+?WTWG?$zxOQ}FNbIy|+Cy0)Z^2To^&BaTQIRD4exIJKw}_|{`@4D^$D9-V{mlDyi*@TkN?`Cf z{k~&DrZhBfD7{%ZZNr%o;X4>LtZsLJtAt+GK;;~`vsAT1(@B<`TAZ-B9Yv6!2uS5T z&()|*tF&MTi8mvTiG=WpxE?8xv00E^^J3<&<7KA*`yX$jZyemc_XU5iX_JGDpdRc2 zH#4)TlME7AX}$RzNNwpdV;QYUGc_SIwrIknC$0N25!-wD2UH+%A0UgWs!3e>IbAhh zfFyv7Yr4}t(z~`GN}A-5Ei}3}3Pi}7#s>@$E}*i}IA@}-+h<(vrby_p?e5z$ z7_-}h$J;|T^YYm>_qpB|kx>q>+9%a{I_;Q;9sIy)?7nLycan1Zx^G!E zpAa>#xV{GUPyV(f(1=~UHC6oklxA=Y;kilXTBLMYX3tu2-l3(`BI!qO;US+!*uw#Y z)0{B81KxCLNz=Zur;;^lyEXL03JkI8o@{#(9HbG zr!|g9^jKAS^xM>mQ0v_cCfJ=3ghr${9CHxY zkO(&xVnolYnlZxbqo+*4v69bjwi=E09FwBCtk-ZKW9ZWJx*%+G5q*g8=A5e5N{q=` zi-}tA76OkIX}aA#gwC|uY%QIO zXi?@qq9eKHb-AJd|0yYQO;zVwLJGF!bzS07wD@kyBF7m2@wXp;e2oAtu0Ox8|L4Dd zeVrf(i1H_@?Z$(iWW_?YiiuWk+%@V!7zL

    N>AW*+w5Cd|sMNuG}NlO{LQ8o1MA=au9_hl( z$7)t{KKfre&r?k?#Bct|@HOXkP1VbY|Mti0|Nf7^{y6&guU~UbWb)in| ztvGVA(qLkd5svfNJfTiZ1s*<**4pdq)mm%4%{biV%pDTtxm>rwHBvM?i8{}$duIIB zX{yLOJbR0}t8gy@!v-VQdEs%_T6?`-Exe<1PH2rA+g!a-YrQpfX*~EdkvM$=sA;M8 zGlLggKW0k}49YKQ{ngvwe#jrMaeTdq_m zPemWI5Oo~TPTh#)XUr1joVr|g0o~98tecq6)_Nb@iyUC5p^2o;IIw^|oo8V-A2>(G zoIik7*EQFxxBug>U$4=y^Ei&<`<&OD|N1`XT>0P%e@`Qp$lf)onXX16CN3}rF%yPLscIjt0WjRu}q9c!wJJTOe%A33)H{=&mn!~NZLOsd z+MKK7DvizR@-sH8m`>=7UGRQiYd+?pG zm-72}KYFC*5nGqoa(T|jkcns3tIJ=0$j?`Qy#^7VqD(Z6`Z-N?t#wW}6E~4#G|;)R z;5G80AgspeTG&CSE^n{;LuI<{ihN@~x7`Mj!#*5qoyo(~OT)jFHj)wI9|Zgoy0=pb z{AA<(?;a9x4_2#N8Jy!HH5QAjcz^e8YDzAd6SCI0Ax+N=Y|>C*@)(V%E!D5l{_^Aa zI+_|a=5cgk`r~U5Srb;HIWhb&TB|qdjfvQx$wZiN^okG#{B{s+WL-;Wb!$C`@1frq zu82VDDY3Gqzt`oQ$bK=`$pX<#L>iz?icx@DIre(lSq0~LnHg04DEFW~I>R;BsFfOO z&ACX)jv#LvfB(xL zKM!2iqw!q&K2Pl5$n5VwhlqTAeSKg0|NDRb>(6T%(~sBj_rJWpMmw*IiFwW&`KhN*; z5|QJp{r!*E*U^xYIOp~2R2V1v7?Am{h-Sragk$}>=5<}?c`^C?7t`MA4bH>2);hUa zwbHazpfvs@lZQ8bsOYIuyHX{~0qQKDx{QoRm%sh-_3Dmrgw7Dl(bmTwKl?b2IhU^W=lAuW z|9Zctf-wJM@N2XV*NEwR>Ywj*nGn*ejm&(qngLZgmNX?LOAhW%c{AGRW@$zW _0 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 DwS*|M literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/HouseYard.png b/examples/starting-expanded-3d-house-horror/assets/HouseYard.png new file mode 100644 index 0000000000000000000000000000000000000000..a190a1b4fdf69f31ad6856301c285d8c19452381 GIT binary patch literal 112105 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�qv(} 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 literal 0 HcmV?d00001 diff --git a/examples/starting-expanded-3d-house-horror/assets/NotoSansArabicUI-Black.ttf b/examples/starting-expanded-3d-house-horror/assets/NotoSansArabicUI-Black.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9541c2cf3718b5a37abd7c08a55f0c4dbc4773fc GIT binary patch literal 338040 zcmd444SZC^^*=m!=H9!>W_J@K@_f&^8;I6l|G($+JkRIz z?0n`s=bk$=cjnBQnRDmP-77R9#AN_oBwRb-rvqCv-ERw_r3(>r{Mw;6-W16D+z`U9 z3sIGJ?M*lL?;U?;jS$l_g-DY(-c(Td-0;eHAr^X&%jj{F$4u?_aLbK2o{Kbv$NiAP;Dsi zXWB5KY316@z~R~+p|rniAAvv?AUCyHd(Z6O#SI2c9%!V&xzu5GS~tJzj5K{2oEa&bOrt|eez0i<`3ocPFg&Rz?-row1B;+_tAE^&BlJt>AB96gf-<3|o z8TOR(#k@POvCQJ?i=x-;8mB8gR-XuWOrHif^9SOt(i@CIeIu3I=&8>~$>wlb=QF+W z`!vU+S}*Ioax~9n$fZkOU1=l4uF&x5N7)_IPZ%M6E8Gr!o4x~Q3-w+4KK&r_>WoWa z*CV1kedoF8dHr;kn7+;&x?bx$=TQzE|A*&X3NN0awj)P!iPHLc{XA%^T|3WrwpdTY za-IAx>7wZ`=EKL|PuE#*AD7HJ>f{v~LyQt*0C0#gg56YOhp`uKy|La*G3aQAG0(Ic z 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�wejg@X=GBa_WNW1UR-2F7H@h?EKL>qo$1qL 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