|
514 | 514 | "};", |
515 | 515 | "", |
516 | 516 | "/**", |
| 517 | + " * @param {gdjs.RuntimeGame} game", |
| 518 | + " * @param {string} imageResourceName", |
| 519 | + " * @returns {CanvasImageSource | null} The image, or null if it's not loaded (yet).", |
| 520 | + " */", |
| 521 | + "const getLoadedImage = (game, imageResourceName) => {", |
| 522 | + " const texture = game.getImageManager().getPIXITexture(imageResourceName);", |
| 523 | + " const source = texture && texture.baseTexture && texture.baseTexture.getDrawableSource();", |
| 524 | + " // An 8 x 8 placeholder is given for images that are not loaded.", |
| 525 | + " return source && source.width > 8 && source.height > 8 ? source : null;", |
| 526 | + "};", |
| 527 | + "", |
| 528 | + "/**", |
517 | 529 | " * Loads heights from an image: black is the lowest, white the highest.", |
518 | 530 | " * Heights have 16 bits of precision when the red channel holds the most", |
519 | 531 | " * significant byte and the green one the least significant (a gray image", |
|
524 | 536 | " * @returns {boolean} true if the image could be read.", |
525 | 537 | " */", |
526 | 538 | "const loadHeightsFromImage = (data, game, imageResourceName) => {", |
527 | | - " const texture = game.getImageManager().getPIXITexture(imageResourceName);", |
528 | | - " const source = texture && texture.baseTexture && texture.baseTexture.getDrawableSource();", |
529 | | - " // An 8 x 8 placeholder is given for images that are not loaded.", |
530 | | - " if (!source || source.width <= 8 || source.height <= 8) return false;", |
| 539 | + " const source = getLoadedImage(game, imageResourceName);", |
| 540 | + " if (!source) return false;", |
531 | 541 | "", |
532 | 542 | " const canvas = document.createElement('canvas');", |
533 | 543 | " canvas.width = source.width;", |
|
1522 | 1532 | " this._strokeChangedSamples = new SampleRectangle();", |
1523 | 1533 | " /** The properties the data was loaded from, to reload it only if they change. */", |
1524 | 1534 | " this.loadedFrom = '';", |
| 1535 | + " /** True when the heightmap image was not loaded yet: the relief is used until it is. */", |
| 1536 | + " this.isWaitingForHeightmap = false;", |
| 1537 | + " this._framesWaitingForHeightmap = 0;", |
1525 | 1538 | " /** The last value of the sculpt data property read or saved. */", |
1526 | 1539 | " this.sculptData = '';", |
1527 | 1540 | " /**", |
|
1566 | 1579 | " const validResolution = RESOLUTIONS.indexOf(resolution) !== -1 ? resolution : DEFAULT_RESOLUTION;", |
1567 | 1580 | " this.sculptData = object._getSculptData();", |
1568 | 1581 | " this.loadedFrom = this._getSourceProperties();", |
| 1582 | + " this.isWaitingForHeightmap = false;", |
1569 | 1583 | "", |
1570 | 1584 | " this.baseData = this._getBaseData(validResolution);", |
1571 | 1585 | " let data = codec.decode(this.sculptData, (resolution) => copyTerrainData(this._getBaseData(resolution)));", |
|
1591 | 1605 | " !!heightmapImage && loadHeightsFromImage(data, object.getRuntimeScene().getGame(), heightmapImage);", |
1592 | 1606 | " if (!isHeightmapLoaded) {", |
1593 | 1607 | " relief.generate(data, object._getRelief(), object._getSeed());", |
| 1608 | + " // The image can still be loading: it's checked again later (see `update`).", |
| 1609 | + " if (heightmapImage) this.isWaitingForHeightmap = true;", |
1594 | 1610 | " }", |
1595 | 1611 | " edits.apply(data, object._getEdits());", |
1596 | 1612 | " // Not kept if the image is missing: it may be loaded later.", |
|
1871 | 1887 | " }", |
1872 | 1888 | "", |
1873 | 1889 | " update() {", |
| 1890 | + " if (this.isWaitingForHeightmap && ++this._framesWaitingForHeightmap % 30 === 0) {", |
| 1891 | + " const game = this.object.getRuntimeScene().getGame();", |
| 1892 | + " if (getLoadedImage(game, this.object._getHeightmapImage())) this.loadFromProperties();", |
| 1893 | + " }", |
1874 | 1894 | " const transform = this._getTransform();", |
1875 | 1895 | " if (transform !== this._transform) {", |
1876 | 1896 | " this._transform = transform;", |
|
3448 | 3468 | "label": "Edits", |
3449 | 3469 | "description": "Changes of the relief or heightmap, 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, negative to lower), flatten (z), smooth (strength) and paint (layer, from 1 to 4, and strength). x, y and radius are fractions (0 to 1) of the terrain size, height and z fractions of its depth. Add toX and toY to change the ground along a line (paths, rivers, ridges). Shown in the scene editor.", |
3450 | 3470 | "group": "Shape", |
| 3471 | + "advanced": true, |
3451 | 3472 | "name": "Edits" |
3452 | 3473 | }, |
3453 | 3474 | { |
|
0 commit comments