@itwin/core-frontend
Version:
iTwin.js frontend components
225 lines • 10.1 kB
JavaScript
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Views
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.EnvironmentDecorations = void 0;
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const core_geometry_1 = require("@itwin/core-geometry");
const ImageUtil_1 = require("./common/ImageUtil");
const IModelApp_1 = require("./IModelApp");
const GraphicType_1 = require("./common/render/GraphicType");
/** @internal */
class EnvironmentDecorations {
_view;
_onLoaded;
_onDispose;
_environment;
_ground;
_sky;
constructor(view, onLoaded, onDispose) {
this._environment = view.displayStyle.environment;
this._view = view;
this._onLoaded = onLoaded;
this._onDispose = onDispose;
this._sky = {};
this.loadSkyBox();
if (this._environment.displayGround)
this.loadGround();
}
[Symbol.dispose]() {
this._ground = undefined;
this._sky.params = this._sky.promise = undefined;
this._onDispose();
}
setEnvironment(env) {
const prev = this._environment;
if (prev === env)
return;
this._environment = env;
// Update ground plane
if (!env.displayGround || env.ground !== prev.ground)
this._ground = undefined;
if (env.displayGround && !this._ground)
this.loadGround();
// Update sky box
if (env.sky !== prev.sky)
this.loadSkyBox();
}
decorate(context) {
const env = this._environment;
let sky;
if (env.displayAtmosphere) {
sky = IModelApp_1.IModelApp.renderSystem.createSkyBox(this.createSkyGradientParams());
}
else if (env.displaySky && this._sky.params) {
sky = IModelApp_1.IModelApp.renderSystem.createSkyBox(this._sky.params);
}
if (sky)
context.setSkyBox(sky);
if (!env.displayGround || !this._ground)
return;
const extents = this._view.getGroundExtents(context.viewport);
if (extents.isNull)
return;
const points = [extents.low.clone(), extents.low.clone(), extents.high.clone(), extents.high.clone()];
points[1].x = extents.high.x;
points[3].x = extents.low.x;
const aboveGround = this._view.isEyePointAbove(extents.low.z);
const params = aboveGround ? this._ground.aboveParams : this._ground.belowParams;
const builder = context.createGraphicBuilder(GraphicType_1.GraphicType.WorldDecoration);
builder.activateGraphicParams(params);
const strokeOptions = new core_geometry_1.StrokeOptions();
strokeOptions.needParams = true;
const polyfaceBuilder = core_geometry_1.PolyfaceBuilder.create(strokeOptions);
polyfaceBuilder.toggleReversedFacetFlag();
const uvParams = [core_geometry_1.Point2d.create(0, 0), core_geometry_1.Point2d.create(1, 0), core_geometry_1.Point2d.create(1, 1), core_geometry_1.Point2d.create(0, 1)];
polyfaceBuilder.addQuadFacet(points, uvParams);
const polyface = polyfaceBuilder.claimPolyface(false);
builder.addPolyface(polyface, true);
context.addDecorationFromBuilder(builder);
}
loadGround() {
(0, core_bentley_1.assert)(undefined === this._ground);
const aboveParams = this.createGroundParams(true);
const belowParams = this.createGroundParams(false);
if (aboveParams && belowParams)
this._ground = { aboveParams, belowParams };
}
createGroundParams(above) {
// Create a gradient texture.
const ground = this._environment.ground;
const values = [0, 0.25, 0.5];
const color = above ? ground.aboveColor : ground.belowColor;
const alpha = above ? 0x80 : 0x85;
const groundColors = [color.withTransparency(0xff), color, color];
groundColors[1] = groundColors[2] = color.withTransparency(alpha);
const gradient = new core_common_1.Gradient.Symb();
gradient.mode = core_common_1.Gradient.Mode.Spherical;
gradient.keys = [{ color: groundColors[0], value: values[0] }, { color: groundColors[1], value: values[1] }, { color: groundColors[2], value: values[2] }];
const texture = IModelApp_1.IModelApp.renderSystem.getGradientTexture(gradient, this._view.iModel);
if (!texture)
return undefined;
// Create a material using the gradient texture
const material = IModelApp_1.IModelApp.renderSystem.createRenderMaterial({
diffuse: { color: core_common_1.ColorDef.white, weight: 0 },
textureMapping: {
texture,
transform: new core_common_1.TextureMapping.Trans2x3(0, 1, 0, 1, 0, 0),
},
});
if (!material)
return undefined;
// Create GraphicParams using the material.
const params = new core_common_1.GraphicParams();
params.lineColor = gradient.keys[0].color;
params.fillColor = core_common_1.ColorDef.white; // Fill should be set to opaque white for gradient texture...
params.material = material;
return params;
}
loadSkyBox() {
const loader = this.loadSkyBoxParams();
if (undefined === loader.preload) {
this.setSky(loader.load());
return;
}
const promise = loader.preload;
this._sky.promise = promise;
loader.preload.then((loaded) => {
if (promise === this._sky.promise)
this.setSky(loaded ? loader.load() : undefined);
}).catch(() => {
if (promise === this._sky.promise)
this.setSky(undefined);
});
}
setSky(params) {
this._sky.promise = undefined;
this._sky.params = params ?? this.createSkyGradientParams();
this._onLoaded();
}
loadSkyBoxParams() {
let load;
let preload;
const sky = this._environment.sky;
if (sky instanceof core_common_1.SkyCube) {
const key = this.createCubeImageKey(sky);
load = () => {
const texture = IModelApp_1.IModelApp.renderSystem.findTexture(key, this._view.iModel);
return texture ? { type: "cube", texture } : undefined;
};
if (!IModelApp_1.IModelApp.renderSystem.findTexture(key, this._view.iModel)) {
// Some faces may use the same image. Only request each image once.
const promises = [];
const specs = new Set([sky.images.front, sky.images.back, sky.images.left, sky.images.right, sky.images.top, sky.images.bottom]);
for (const spec of specs)
promises.push(this.imageFromSpec(spec));
preload = Promise.all(promises).then((images) => {
const idToImage = new Map();
let index = 0;
for (const spec of specs) {
const image = images[index++];
if (!image)
return false;
else
idToImage.set(spec, image);
}
const params = new core_common_1.RenderTextureParams(key, core_common_1.RenderTexture.Type.SkyBox);
const txImgs = [
idToImage.get(sky.images.front), idToImage.get(sky.images.back), idToImage.get(sky.images.top),
idToImage.get(sky.images.bottom), idToImage.get(sky.images.right), idToImage.get(sky.images.left),
];
return undefined !== IModelApp_1.IModelApp.renderSystem.createTextureFromCubeImages(txImgs[0], txImgs[1], txImgs[2], txImgs[3], txImgs[4], txImgs[5], this._view.iModel, params);
});
}
}
else if (sky instanceof core_common_1.SkySphere) {
load = () => {
const texture = IModelApp_1.IModelApp.renderSystem.findTexture(sky.image, this._view.iModel);
return texture ? {
type: "sphere",
texture,
rotation: 0,
zOffset: this._view.iModel.globalOrigin.z,
} : undefined;
};
if (!IModelApp_1.IModelApp.renderSystem.findTexture(sky.image, this._view.iModel)) {
preload = this.imageFromSpec(sky.image).then((image) => {
if (!image)
return false;
return undefined !== IModelApp_1.IModelApp.renderSystem.createTexture({
image: { source: image },
ownership: { iModel: this._view.iModel, key: sky.image },
});
});
}
}
else {
load = () => this.createSkyGradientParams();
}
return { load, preload };
}
createCubeImageKey(sky) {
const i = sky.images;
return `skycube:${i.front}:${i.back}:${i.left}:${i.right}:${i.top}:${i.bottom}`;
}
createSkyGradientParams() {
return {
type: "gradient",
gradient: this._environment.sky.gradient,
zOffset: this._view.iModel.globalOrigin.z,
};
}
async imageFromSpec(spec) {
if (core_bentley_1.Id64.isValidId64(spec))
return (await IModelApp_1.IModelApp.renderSystem.loadTextureImage(spec, this._view.iModel))?.image;
return (0, ImageUtil_1.tryImageElementFromUrl)(spec);
}
}
exports.EnvironmentDecorations = EnvironmentDecorations;
//# sourceMappingURL=EnvironmentDecorations.js.map