"use strict";
import { Box } from "../../bv/Box.js";
import { Sphere } from "../../bv/Sphere.js";
import { Extent } from "../../Extent";
import { Layer } from "../../layer/Layer.js";
import { LonLat } from "../../LonLat";
import { Ray } from "../../math/Ray.js";
import { Vec3 } from "../../math/Vec3";
import * as mercator from "../../mercator";
import { EPSG3857 } from "../../proj/EPSG3857.js";
import { E, N, NOTRENDERING, OPSIDE, S, W } from "../../quadTree/quadTree.js";
import * as segmentHelper from "../../segment/segmentHelper.js";
import { getMatrixSubArray } from "../../utils/shared";
export const MAX_NORMAL_ZOOM = 7;
var _tempHigh = new Vec3();
var _tempLow = new Vec3();
var _RenderingSlice = function (p) {
this.layers = [];
this.tileOffsetArr = new Float32Array(p.SLICE_SIZE_4);
this.visibleExtentOffsetArr = new Float32Array(p.SLICE_SIZE_4);
this.layerOpacityArr = new Float32Array(p.SLICE_SIZE);
this.clear = function () {
this.layers = null;
this.tileOffsetArr = null;
this.visibleExtentOffsetArr = null;
this.layerOpacityArr = null;
};
};
let _v0 = new Vec3(),
_v1 = new Vec3(),
_v2 = new Vec3(),
_v3 = new Vec3();
let _ray = new Ray(),
_rayEx = new Ray();
window.ELLNORM = false;
const _S = new Array(4);
_S[N] = 0;
_S[E] = 1;
_S[S] = 1;
_S[W] = 0;
const _V = new Array(4);
_V[N] = false;
_V[E] = true;
_V[S] = false;
_V[W] = true;
window.BBSC = 100;
/**
* Planet segment Web Mercator tile class that stored and rendered with quad tree.
* @class
* @param {quadTree.Node} node - Segment node.
* @param {Planet} planet - Current planet scene.
* @param {Number} tileZoom - Zoom index.
* @param {Extent} extent - Segment extent.
*/
class Segment {
/**
* @param {quadTree.Node} node - Segment node.
* @param {Planet} planet - Current planet scene.
* @param {number} tileZoom - Zoom index.
* @param {Extent} extent - Segment extent.
*/
constructor(node, planet, tileZoom, extent) {
this.isPole = false;
this._tileGroup = 0;
this._projection = EPSG3857;
/**
* Quad tree node of the segment.
* @type {quadTree.Node}
*/
this.node = node;
/**
* Planet pointer.
* @type {Planet}
*/
this.planet = planet;
/**
* WebGl handler pointer.
* @type {Handler}
*/
this.handler = planet.renderer.handler;
/**
* Segment bounding sphere
* @type {Sphere}
*/
this.bsphere = new Sphere();
this._plainRadius = 0;
/**
* Segment bounding box.
* @type {Box}
*/
this.bbox = new Box();
this._swNorm = null;
this._nwNorm = null;
this._seNorm = null;
this._neNorm = null;
/**
* Geographical extent.
* @type {Extent}
*/
this._extent = extent;
this._extentLonLat = null;
/**
* Vertices grid size.
* @type {number}
*/
this.gridSize = planet.terrain.gridSizeByZoom[tileZoom];
this.fileGridSize = 0;
/**
* Tile zoom index.
* @type {number}
*/
this.tileZoom = tileZoom;
/**
* Horizontal tile index.
* @type {number}
*/
this.tileX = 0;
this.tileXE = 0;
this.tileXW = 0;
this.tileYN = 0;
this.tileYS = 0;
/**
* Vertical tile index.
* @type {number}
*/
this.tileY = 0;
this.tileIndex = "";
this._assignTileIndexes();
/**
* Texture materials array.
* @type {Array.<planetSegment.Material>}
*/
this.materials = [];
/**
* Plain segment vertices was created.
* @type {boolean}
*/
this.plainReady = false;
/**
* Segment is ready to create plain vertices.
* @type {boolean}
*/
this.initialized = false;
/**
* Normal map is allready made.
* @type {boolean}
*/
this.normalMapReady = false;
/**
* Parent normal map is made allready(optimization parameter).
* @type {boolean}
*/
this.parentNormalMapReady = false;
/**
* Terrain is allready applied flag.
* @type {boolean}
*/
this.terrainReady = false;
/**
* Terrain is loading now flag.
* @type {boolean}
*/
this.terrainIsLoading = false;
/**
* Terrain existing flag.
* @type {boolean}
*/
this.terrainExists = false;
this.plainVertices = null;
this.plainVerticesHigh = null;
this.plainVerticesLow = null;
this.plainNormals = null;
this.terrainVertices = null;
this.terrainVerticesHigh = null;
this.terrainVerticesLow = null;
this.noDataVertices = null;
this.tempVertices = null;
this.tempVerticesHigh = null;
this.tempVerticesLow = null;
this.normalMapTexture = null;
this.normalMapTextureBias = new Float32Array(3);
this.normalMapVertices = null;
this.normalMapVerticesHigh = null;
this.normalMapVerticesLow = null;
this.normalMapNormals = null;
this.vertexNormalBuffer = null;
this.vertexPositionBuffer = null;
this.vertexPositionBufferHigh = null;
this.vertexPositionBufferLow = null;
this.vertexTextureCoordBuffer = null;
this._globalTextureCoordinates = new Float32Array(4);
this._inTheQueue = false;
this._appliedNeighborsZoom = [0, 0, 0, 0];
this._renderingSlices = [];
this._indexBuffer = null;
this.readyToEngage = false;
this.plainProcessing = false;
}
/**
* Returns that segment good for rendering with camera by current lod ratio.
* @public
* @param {Camera} camera - Camera object.
* @returns {boolean} -
*/
acceptForRendering(camera) {
return camera.projectedSize(this.bsphere.center, this._plainRadius) < (256 / this.planet._lodRatio);
}
/**
* Returns entity terrain point.
* @public
* @param {Entity} entity - Entity.
* @param {Vec3} res - Point coordinates.
* @param {Vec3} [normal] - Terrain point normal.
* @returns {Vec3} -
*/
getEntityTerrainPoint(entity, res) {
return this.getTerrainPoint(entity._cartesian, entity._lonLatMerc, res);
}
isEntityInside(e) {
return this._extent.isInside(e._lonLatMerc);
}
/**
* Returns distance from object to terrain coordinates and terrain point that calculates out in the res parameter.
* @public
* @param {Vec3} xyz - Cartesian object position.
* @param {LonLat} insideSegmentPosition - Geodetic object position.
* @param {Vec3} [res] - Result cartesian coordinates on the terrain.
* @param {Vec3} [normal] - Terrain point normal.
* @returns {number} -
*/
getTerrainPoint(xyz, insideSegmentPosition, res) {
let verts = this.tempVertices;
if (verts && verts.length) {
let norm = this.planet.ellipsoid.getSurfaceNormal3v(xyz);
_ray.set(xyz, norm.negateTo());
let ne = this._extent.northEast,
sw = this._extent.southWest,
size = Math.sqrt(verts.length / 3) - 1;
let xmax = ne.lon,
ymax = ne.lat,
xmin = sw.lon,
ymin = sw.lat,
x = insideSegmentPosition.lon,
y = insideSegmentPosition.lat;
let sxn = xmax - xmin,
syn = ymax - ymin;
let qx = sxn / size,
qy = syn / size;
let xn = x - xmin,
yn = y - ymin;
let indX = Math.floor(xn / qx),
indY = Math.floor(size - yn / qy);
let ind_v0 = ((size + 1) * indY + indX) * 3;
let ind_v2 = ((size + 1) * (indY + 1) + indX) * 3;
_v0.set(verts[ind_v0], verts[ind_v0 + 1], verts[ind_v0 + 2]);
_v1.set(verts[ind_v0 + 3], verts[ind_v0 + 4], verts[ind_v0 + 5]);
_v2.set(verts[ind_v2], verts[ind_v2 + 1], verts[ind_v2 + 2]);
let d = _ray.hitTriangleRes(_v0, _v1, _v2, res);
if (d === Ray.INSIDE) {
return xyz.distance(res);
} else if (d === Ray.AWAY) {
_rayEx.set(xyz, norm);
let d = _rayEx.hitTriangleRes(_v0, _v1, _v2, res);
if (d === Ray.INSIDE) {
return -xyz.distance(res);
}
}
_v3.set(verts[ind_v2 + 3], verts[ind_v2 + 4], verts[ind_v2 + 5]);
d = _ray.hitTriangleRes(_v1, _v3, _v2, res);
if (d === Ray.INSIDE) {
return xyz.distance(res);
} else if (d === Ray.AWAY) {
_rayEx.set(xyz, norm);
let d = _rayEx.hitTriangleRes(_v1, _v3, _v2, res);
if (d === Ray.INSIDE) {
return -xyz.distance(res);
}
}
if (d === Ray.AWAY) {
return -xyz.distance(res);
}
return xyz.distance(res);
} else {
return xyz.distance(this.planet.ellipsoid.hitRay(_ray.origin, _ray.direction));
}
}
/**
* Project wgs86 to segment native projection.
* @public
* @param {LonLat} lonlat - Coordinates to project.
* @returns {LonLat} -
*/
projectNative(lonLat) {
return lonLat.forwardMercator();
}
/**
*
* @param {boolean} forceLoading
*/
loadTerrain(forceLoading) {
if (this.tileZoom < this.planet.terrain.minZoom) {
this.terrainIsLoading = true;
this.elevationsNotExists();
if (!this._inTheQueue) {
this.planet._normalMapCreator.queue(this);
}
} else {
if (this.tileZoom > this.planet.terrain.maxZoom) {
this.elevationsNotExists();
} else if (!this.terrainIsLoading && !this.terrainReady) {
this.planet.terrain.loadTerrain(this, forceLoading);
}
}
}
/**
* Terrain obtained from server.
* @param {Float32Array} elevations - Elevation data.
*/
elevationsExists(elevations) {
const segment = this;
if (this.plainReady && this.terrainIsLoading) {
this.planet._terrainWorker.make(segment, elevations);
this.plainVerticesHigh = null;
this.plainVerticesLow = null;
this.normalMapVerticesHigh = null;
this.normalMapVerticesLow = null;
if (!this.planet.terrain.equalizeVertices) {
this.tempVerticesHigh = null;
this.tempVerticesLow = null;
}
}
}
_checkEqualization(neighborSide, neigborNode) {
return (
neigborNode && this.tileZoom >= neigborNode.segment.tileZoom
//&&
//(
// this.node.equalizedNeighborId[neighborSide] !== neigborNode.appliedTerrainNodeId ||
// this.node.equalizedNeighborGridSize[neighborSide] !== neigborNode.segment.gridSize
//||
// neigborNode.equalizedNeighborId[OPSIDE[neighborSide]] !== this.node.appliedTerrainNodeId ||
// neigborNode.equalizedNeighborGridSize[OPSIDE[neighborSide]] !== this.gridSize
//)
);
}
equalize() {
if (this.tileZoom < 8 || this.gridSize < 2) {
return;
}
this.readyToEngage = true;
let nn = this.node.neighbors;
let v = this.tempVertices,
vHigh = this.tempVerticesHigh,
vLow = this.tempVerticesLow;
let gs = this.gridSize,
gsOne = gs + 1;
let n = nn[N][0];
if (this._checkEqualization(N, n)) {
//this.node.equalizedNeighborId[N] = n.appliedTerrainNodeId;
//this.node.equalizedNeighborGridSize[N] = n.segment.gridSize;
//n.equalizedNeighborId[OPSIDE[N]] = this.node.appliedTerrainNodeId;
//n.equalizedNeighborGridSize[OPSIDE[N]] = this.gridSize;
this.readyToEngage = true;
let offset = this.node.getOffsetOppositeNeighbourSide(n, N);
let nv = n.segment.tempVertices,
nvHigh = n.segment.tempVerticesHigh,
nvLow = n.segment.tempVerticesLow;
let n_gs = n.segment.gridSize,
n_gsOne = n_gs + 1;
let dz = 1 / (1 << (this.tileZoom - n.segment.tileZoom));
let inc = Math.max(gs / (n_gs * dz), 1),
n_inc = Math.max((n_gs * dz) / gs, 1),
n_offset = offset * n_gs;
for (let k = 0, nk = n_offset; k < gsOne; k += inc, nk += n_inc) {
const index = k * 3;
const n_index = (n_gsOne * n_gs + nk) * 3;
v[index] = nv[n_index];
v[index + 1] = nv[n_index + 1];
v[index + 2] = nv[n_index + 2];
vHigh[index] = nvHigh[n_index];
vHigh[index + 1] = nvHigh[n_index + 1];
vHigh[index + 2] = nvHigh[n_index + 2];
vLow[index] = nvLow[n_index];
vLow[index + 1] = nvLow[n_index + 1];
vLow[index + 2] = nvLow[n_index + 2];
}
}
n = nn[E][0];
if (this._checkEqualization(E, n)) {
//this.node.equalizedNeighborId[E] = n.appliedTerrainNodeId;
//this.node.equalizedNeighborGridSize[E] = n.segment.gridSize;
//n.equalizedNeighborId[OPSIDE[E]] = this.node.appliedTerrainNodeId;
//n.equalizedNeighborGridSize[OPSIDE[E]] = this.gridSize;
this.readyToEngage = true;
let offset = this.node.getOffsetOppositeNeighbourSide(n, E);
let nv = n.segment.tempVertices,
nvHigh = n.segment.tempVerticesHigh,
nvLow = n.segment.tempVerticesLow;
let n_gs = n.segment.gridSize,
n_gsOne = n_gs + 1;
let dz = 1 / (1 << (this.tileZoom - n.segment.tileZoom));
let inc = Math.max(gs / (n_gs * dz), 1),
n_inc = Math.max((n_gs * dz) / gs, 1),
n_offset = offset * n_gs;
for (let k = 0, nk = n_offset; k < gsOne; k += inc, nk += n_inc) {
const index = (gsOne * k + gs) * 3;
const n_index = n_gsOne * nk * 3;
v[index] = nv[n_index];
v[index + 1] = nv[n_index + 1];
v[index + 2] = nv[n_index + 2];
vHigh[index] = nvHigh[n_index];
vHigh[index + 1] = nvHigh[n_index + 1];
vHigh[index + 2] = nvHigh[n_index + 2];
vLow[index] = nvLow[n_index];
vLow[index + 1] = nvLow[n_index + 1];
vLow[index + 2] = nvLow[n_index + 2];
}
}
n = nn[S][0];
if (this._checkEqualization(S, n)) {
//this.node.equalizedNeighborId[S] = n.appliedTerrainNodeId;
//this.node.equalizedNeighborGridSize[S] = n.segment.gridSize;
//n.equalizedNeighborId[OPSIDE[S]] = this.node.appliedTerrainNodeId;
//n.equalizedNeighborGridSize[OPSIDE[S]] = this.gridSize;
this.readyToEngage = true;
let offset = this.node.getOffsetOppositeNeighbourSide(n, S);
let nv = n.segment.tempVertices,
nvHigh = n.segment.tempVerticesHigh,
nvLow = n.segment.tempVerticesLow;
let n_gs = n.segment.gridSize; // n_gsOne = n_gs + 1;
let dz = 1 / (1 << (this.tileZoom - n.segment.tileZoom));
let inc = Math.max(gs / (n_gs * dz), 1),
n_inc = Math.max((n_gs * dz) / gs, 1),
n_offset = offset * n_gs;
for (let k = 0, nk = n_offset; k < gsOne; k += inc, nk += n_inc) {
const index = (gsOne * gs + k) * 3;
const n_index = nk * 3;
v[index] = nv[n_index];
v[index + 1] = nv[n_index + 1];
v[index + 2] = nv[n_index + 2];
vHigh[index] = nvHigh[n_index];
vHigh[index + 1] = nvHigh[n_index + 1];
vHigh[index + 2] = nvHigh[n_index + 2];
vLow[index] = nvLow[n_index];
vLow[index + 1] = nvLow[n_index + 1];
vLow[index + 2] = nvLow[n_index + 2];
}
}
n = nn[W][0];
if (this._checkEqualization(W, n)) {
//this.node.equalizedNeighborId[W] = n.appliedTerrainNodeId;
//this.node.equalizedNeighborGridSize[W] = n.segment.gridSize;
//n.equalizedNeighborId[OPSIDE[W]] = this.node.appliedTerrainNodeId;
//n.equalizedNeighborGridSize[OPSIDE[W]] = this.gridSize;
this.readyToEngage = true;
let offset = this.node.getOffsetOppositeNeighbourSide(n, W);
let nv = n.segment.tempVertices,
nvHigh = n.segment.tempVerticesHigh,
nvLow = n.segment.tempVerticesLow;
let n_gs = n.segment.gridSize,
n_gsOne = n_gs + 1;
let dz = 1 / (1 << (this.tileZoom - n.segment.tileZoom));
let inc = Math.max(gs / (n_gs * dz), 1),
n_inc = Math.max((n_gs * dz) / gs, 1),
n_offset = offset * n_gs;
for (let k = 0, nk = n_offset; k < gsOne; k += inc, nk += n_inc) {
const index = gsOne * k * 3;
const n_index = (n_gsOne * nk + n_gs) * 3;
v[index] = nv[n_index];
v[index + 1] = nv[n_index + 1];
v[index + 2] = nv[n_index + 2];
vHigh[index] = nvHigh[n_index];
vHigh[index + 1] = nvHigh[n_index + 1];
vHigh[index + 2] = nvHigh[n_index + 2];
vLow[index] = nvLow[n_index];
vLow[index + 1] = nvLow[n_index + 1];
vLow[index + 2] = nvLow[n_index + 2];
}
}
}
engage() {
this.readyToEngage = false;
this.createCoordsBuffers(this.tempVerticesHigh, this.tempVerticesLow, this.gridSize);
}
_plainSegmentWorkerCallback(data) {
this.plainProcessing = false;
if (this.initialized && !this.terrainReady) {
this.plainVertices = data.plainVertices;
this.plainVerticesHigh = data.plainVerticesHigh;
this.plainVerticesLow = data.plainVerticesLow;
this.plainNormals = data.plainNormals;
this.normalMapNormals = data.normalMapNormals;
this.normalMapVertices = data.normalMapVertices;
this.normalMapVerticesHigh = data.normalMapVerticesHigh;
this.normalMapVerticesLow = data.normalMapVerticesLow;
this.terrainVertices = this.plainVertices;
this.terrainVerticesHigh = this.plainVerticesHigh;
this.terrainVerticesLow = this.plainVerticesLow;
this.fileGridSize = Math.sqrt(data.normalMapVertices.length / 3) - 1;
this._plainRadius = data.plainRadius;
this.plainReady = true;
}
}
_terrainWorkerCallback(data) {
if (this.plainReady) {
this.readyToEngage = true;
this.normalMapNormals = null;
this.normalMapVertices = null;
this.normalMapVerticesHigh = null;
this.normalMapVerticesLow = null;
this.terrainVertices = null;
this.terrainVerticesHigh = null;
this.terrainVerticesLow = null;
this.noDataVertices = null;
this.tempVertices = null;
this.tempVerticesHigh = null;
this.tempVerticesLow = null;
this.normalMapNormals = data.normalMapNormals;
this.normalMapVertices = data.normalMapVertices;
this.normalMapVerticesHigh = data.normalMapVerticesHigh;
this.normalMapVerticesLow = data.normalMapVerticesLow;
this.terrainVertices = data.terrainVertices;
this.terrainVerticesHigh = data.terrainVerticesHigh;
this.terrainVerticesLow = data.terrainVerticesLow;
this.noDataVertices = data.noDataVertices;
this.tempVertices = this.terrainVertices;
this.tempVerticesHigh = this.terrainVerticesHigh;
this.tempVerticesLow = this.terrainVerticesLow;
this.setBoundingVolumeArr(data.bounds);
//var b = data.bounds;
//this.setBoundingSphere(
// b[0] + (b[1] - b[0]) * 0.5,
// b[2] + (b[3] - b[2]) * 0.5,
// b[4] + (b[5] - b[4]) * 0.5,
// new Vec3(b[0], b[2], b[4])
//);
this.gridSize = Math.sqrt(this.terrainVertices.length / 3) - 1;
this.node.appliedTerrainNodeId = this.node.nodeId;
this.terrainReady = true;
this.terrainIsLoading = false;
this.parentNormalMapReady = true;
this.terrainExists = true;
if (!this.normalMapTexturePtr) {
var nmc = this.planet._normalMapCreator;
this.normalMapTexturePtr = this.planet.renderer.handler.createEmptyTexture_l(
nmc._width,
nmc._height
);
}
if (this.planet.lightEnabled) {
this.planet._normalMapCreator.queue(this);
}
}
}
/**
* Terrain is not obtained or not exists on the server.
*/
elevationsNotExists() {
if (this.planet && this.tileZoom <= this.planet.terrain.maxZoom) {
if (this.plainReady && this.terrainIsLoading) {
this.terrainIsLoading = false;
this.node.appliedTerrainNodeId = this.node.nodeId;
if (this.planet.lightEnabled && !this._inTheQueue) {
this.planet._normalMapCreator.queue(this);
}
this.readyToEngage = true;
}
this.terrainVertices = this.plainVertices;
this.terrainVerticesHigh = this.plainVerticesHigh;
this.terrainVerticesLow = this.plainVerticesLow;
this.tempVertices = this.terrainVertices;
this.tempVerticesHigh = this.terrainVerticesHigh;
this.tempVerticesLow = this.terrainVerticesLow;
this.noDataVertices = null;
this.fileGridSize = Math.sqrt(this.terrainVertices.length / 3) - 1;
this.gridSize = this.fileGridSize;
this.terrainReady = true;
this.terrainExists = false;
}
}
_normalMapEdgeEqualize(side) {
let nn = this.node.neighbors;
let n = nn[side][0];
let maxZ = this.planet.terrain.maxZoom;
if (this.tileZoom === maxZ) {
if (!(nn[0].length || nn[1].length || nn[2].length || nn[3].length)) {
n = this.node.getEqualNeighbor(side);
}
}
let b = n && n.segment,
s = this;
if (
n &&
b &&
b.terrainReady &&
b.terrainExists &&
b.tileZoom <= maxZ &&
s._appliedNeighborsZoom[side] !== b.tileZoom
) {
s._appliedNeighborsZoom[side] = b.tileZoom;
let seg_a = s.normalMapNormals,
seg_b = b.normalMapNormals;
if (!(seg_a && seg_b)) return;
let seg_a_raw = s.normalMapNormals,
seg_b_raw = b.normalMapNormals;
// let seg_a_verts = s.terrainVertices,
// seg_b_verts = s.terrainVertices;
let s_gs = Math.sqrt(seg_a.length / 3),
// b_gs = Math.sqrt(seg_b.length / 3),
s_gs1 = s_gs - 1;
// b_gs1 = b_gs - 1;
const i_a = s_gs1 * _S[side];
let nx, ny, nz, q;
if (s.tileZoom === b.tileZoom) {
const i_b = s_gs1 - i_a;
if (_V[side]) {
for (let k = 0; k < s_gs; k++) {
let vInd_a = (k * s_gs + i_a) * 3,
vInd_b = (k * s_gs + i_b) * 3;
nx = seg_a_raw[vInd_a] + seg_b_raw[vInd_b];
ny = seg_a_raw[vInd_a + 1] + seg_b_raw[vInd_b + 1];
nz = seg_a_raw[vInd_a + 2] + seg_b_raw[vInd_b + 2];
q = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz);
seg_b[vInd_b] = seg_a[vInd_a] = nx * q;
seg_b[vInd_b + 1] = seg_a[vInd_a + 1] = ny * q;
seg_b[vInd_b + 2] = seg_a[vInd_a + 2] = nz * q;
}
} else {
for (let k = 0; k < s_gs; k++) {
let vInd_a = (i_a * s_gs + k) * 3,
vInd_b = (i_b * s_gs + k) * 3;
nx = seg_a_raw[vInd_a] + seg_b_raw[vInd_b];
ny = seg_a_raw[vInd_a + 1] + seg_b_raw[vInd_b + 1];
nz = seg_a_raw[vInd_a + 2] + seg_b_raw[vInd_b + 2];
q = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz);
seg_b[vInd_b] = seg_a[vInd_a] = nx * q;
seg_b[vInd_b + 1] = seg_a[vInd_a + 1] = ny * q;
seg_b[vInd_b + 2] = seg_a[vInd_a + 2] = nz * q;
}
}
if (!b._inTheQueue && b._appliedNeighborsZoom[OPSIDE[side]] !== s.tileZoom) {
b._appliedNeighborsZoom[OPSIDE[side]] = s.tileZoom;
s.planet._normalMapCreator.queue(b);
}
}
}
}
applyTerrain(elevations) {
if (elevations) {
this.elevationsExists(elevations);
} else {
this.elevationsNotExists();
}
}
/**
* Delete segment gl buffers.
*/
deleteBuffers() {
var gl = this.handler.gl;
gl.deleteBuffer(this.vertexNormalBuffer);
gl.deleteBuffer(this.vertexPositionBuffer);
gl.deleteBuffer(this.vertexPositionBufferHigh);
gl.deleteBuffer(this.vertexPositionBufferLow);
this.vertexNormalBuffer = null;
this.vertexPositionBuffer = null;
this.vertexPositionBufferHigh = null;
this.vertexPositionBufferLow = null;
this.vertexTextureCoordBuffer = null;
}
/**
* Delete materials.
*/
deleteMaterials() {
var m = this.materials;
for (let i = 0; i < m.length; i++) {
var mi = m[i];
if (mi) {
mi.clear();
}
}
this.materials.length = 0;
}
/**
* Delete elevation data.
*/
deleteElevations() {
this.terrainExists = false;
this.terrainReady = false;
this.terrainIsLoading = false;
this.normalMapVertices = null;
this.normalMapVerticesHigh = null;
this.normalMapVerticesLow = null;
this.normalMapNormals = null;
this.tempVertices = null;
this.tempVerticesHigh = null;
this.tempVerticesLow = null;
this.terrainVertices = null;
this.terrainVerticesHigh = null;
this.terrainVerticesLow = null;
this.noDataVertices = null;
this.plainVertices = null;
this.plainVerticesHigh = null;
this.plainVerticesLow = null;
this.plainNormals = null;
if (this.normalMapReady) {
this.handler.gl.deleteTexture(this.normalMapTexture);
}
this.normalMapReady = false;
this.parentNormalMapReady = false;
this._appliedNeighborsZoom = [0, 0, 0, 0];
this.normalMapTextureBias[0] = 0;
this.normalMapTextureBias[1] = 0;
this.normalMapTextureBias[2] = 1;
this._inTheQueue = false;
}
/**
* Clear but not destroy segment data.
*/
clearSegment() {
this.plainReady = false;
this.initialized = false;
this.deleteBuffers();
this.deleteMaterials();
this.deleteElevations();
}
/**
* Removes cache records.
*/
_freeCache() {
this.planet._quadTreeNodesCacheMerc[this.tileIndex] = null;
delete this.planet._quadTreeNodesCacheMerc[this.tileIndex];
}
/**
* Clear and destroy all segment data.
*/
destroySegment() {
this._freeCache();
this.clearSegment();
var i = this._renderingSlices.length;
while (i--) {
this._renderingSlices[i].clear();
}
this._renderingSlices = null;
this.node = null;
this.planet = null;
this.handler = null;
this.bbox = null;
this.bsphere = null;
this._extent = null;
this.materials = null;
this.plainVertices = null;
this.plainVerticesHigh = null;
this.plainVerticesLow = null;
this.plainNormals = null;
this.terrainVertices = null;
this.terrainVerticesHigh = null;
this.terrainVerticesLow = null;
this.noDataVertices = null;
this.tempVertices = null;
this.tempVerticesHigh = null;
this.tempVerticesLow = null;
this.normalMapTexture = null;
this.normalMapTextureBias = null;
this.normalMapVertices = null;
this.normalMapVerticesHigh = null;
this.normalMapVerticesLow = null;
this.normalMapNormals = null;
this.vertexNormalBuffer = null;
this.vertexPositionBuffer = null;
this.vertexPositionBufferHigh = null;
this.vertexPositionBufferLow = null;
this.vertexTextureCoordBuffer = null;
this._projection = null;
this._appliedNeighborsZoom = null;
this._globalTextureCoordinates = null;
}
_setExtentLonLat() {
this._extentLonLat = this._extent.inverseMercator();
}
/**
* Creates bound volumes by segment geographical extent.
*/
createBoundsByExtent() {
var ellipsoid = this.planet.ellipsoid,
extent = this._extentLonLat;
var coord_sw = ellipsoid.geodeticToCartesian(extent.southWest.lon, extent.southWest.lat);
var coord_ne = ellipsoid.geodeticToCartesian(extent.northEast.lon, extent.northEast.lat);
// check for zoom
if (this.tileZoom <= MAX_NORMAL_ZOOM) {
var coord_nw = ellipsoid.geodeticToCartesian(
extent.southWest.lon,
extent.northEast.lat
);
var coord_se = ellipsoid.geodeticToCartesian(
extent.northEast.lon,
extent.southWest.lat
);
this._swNorm = coord_sw.normal();
this._nwNorm = coord_nw.normal();
this._neNorm = coord_ne.normal();
this._seNorm = coord_se.normal();
}
this.setBoundingVolume3v(coord_sw, coord_ne);
}
createBoundsByParent() {
let pn = this.node;
while (pn.parentNode && !pn.segment.terrainReady) {
pn = pn.parentNode;
}
let dZ2 = 1 << (this.tileZoom - pn.segment.tileZoom);
let offsetX = this.tileX - pn.segment.tileX * dZ2,
offsetY = this.tileY - pn.segment.tileY * dZ2;
if (pn.segment.terrainReady && pn.segment.tileZoom >= this.planet.terrain.minZoom) {
let gridSize = pn.segment.gridSize / dZ2;
if (gridSize >= 1.0) {
//
// (*) Actually, we get parent whole bounding volume
//
this.bsphere.center.x = pn.segment.bsphere.center.x;
this.bsphere.center.y = pn.segment.bsphere.center.y;
this.bsphere.center.z = pn.segment.bsphere.center.z;
this.bsphere.radius = pn.segment.bsphere.radius;
if (this.tileZoom <= MAX_NORMAL_ZOOM) {
let i0 = gridSize * offsetY;
let j0 = gridSize * offsetX;
let pnGsOne = pn.segment.gridSize + 1;
let ind_sw = 3 * ((i0 + gridSize) * pnGsOne + j0),
ind_nw = 3 * (i0 * pnGsOne + j0),
ind_ne = 3 * (i0 * pnGsOne + j0 + gridSize),
ind_se = 3 * ((i0 + gridSize) * pnGsOne + j0 + gridSize);
let pVerts = pn.segment.tempVertices;
let v_sw = new Vec3(pVerts[ind_sw], pVerts[ind_sw + 1], pVerts[ind_sw + 2]),
v_ne = new Vec3(pVerts[ind_ne], pVerts[ind_ne + 1], pVerts[ind_ne + 2]);
// check for segment zoom
let v_nw = new Vec3(pVerts[ind_nw], pVerts[ind_nw + 1], pVerts[ind_nw + 2]),
v_se = new Vec3(pVerts[ind_se], pVerts[ind_se + 1], pVerts[ind_se + 2]);
this._swNorm = v_sw.normal();
this._nwNorm = v_nw.normal();
this._neNorm = v_ne.normal();
this._seNorm = v_se.normal();
}
} else {
let pseg = pn.segment;
let i0 = Math.floor(gridSize * offsetY),
j0 = Math.floor(gridSize * offsetX);
let insideSize = 1.0 / gridSize;
let t_i0 = offsetY - insideSize * i0,
t_j0 = offsetX - insideSize * j0;
let bigOne;
if (pseg.gridSize === 1) {
bigOne = pseg.tempVertices;
} else {
bigOne = getMatrixSubArray(pseg.tempVertices, pseg.gridSize, i0, j0, 1);
}
let v_lt = new Vec3(bigOne[0], bigOne[1], bigOne[2]),
v_rb = new Vec3(bigOne[9], bigOne[10], bigOne[11]);
let vn = new Vec3(
bigOne[3] - bigOne[0],
bigOne[4] - bigOne[1],
bigOne[5] - bigOne[2]
),
vw = new Vec3(
bigOne[6] - bigOne[0],
bigOne[7] - bigOne[1],
bigOne[8] - bigOne[2]
),
ve = new Vec3(
bigOne[3] - bigOne[9],
bigOne[4] - bigOne[10],
bigOne[5] - bigOne[11]
),
vs = new Vec3(
bigOne[6] - bigOne[9],
bigOne[7] - bigOne[10],
bigOne[8] - bigOne[11]
);
let vi_y = t_i0,
vi_x = t_j0;
let coords_lt, coords_rb;
if (vi_y + vi_x < insideSize) {
coords_lt = Vec3.add(
vn.scaleTo(vi_x / insideSize),
vw.scaleTo(vi_y / insideSize)
).addA(v_lt);
} else {
coords_lt = Vec3.add(
vs.scaleTo(1 - vi_x / insideSize),
ve.scaleTo(1 - vi_y / insideSize)
).addA(v_rb);
}
vi_y = t_i0 + 1;
vi_x = t_j0 + 1;
if (vi_y + vi_x < insideSize) {
coords_rb = Vec3.add(
vn.scaleTo(vi_x / insideSize),
vw.scaleTo(vi_y / insideSize)
).addA(v_lt);
} else {
coords_rb = Vec3.add(
vs.scaleTo(1 - vi_x / insideSize),
ve.scaleTo(1 - vi_y / insideSize)
).addA(v_rb);
}
this.setBoundingVolume3v(coords_lt, coords_rb);
}
} else {
this.createBoundsByExtent();
}
}
setBoundingSphere(x, y, z, v) {
this.bsphere.center.x = x;
this.bsphere.center.y = y;
this.bsphere.center.z = z;
this.bsphere.radius = this.bsphere.center.distance(v);
}
setBoundingVolume(xmin, ymin, zmin, xmax, ymax, zmax) {
this.bbox.setFromBoundsArr([xmin, ymin, zmin, xmax, ymax, zmax]);
let x = xmin + (xmax - xmin) * 0.5,
y = ymin + (ymax - ymin) * 0.5,
z = zmin + (zmax - zmin) * 0.5;
this.bsphere.center.set(x, y, z);
this.bsphere.radius = this.bsphere.center.distance(new Vec3(xmin, ymin, zmin));
}
setBoundingVolume3v(vmin, vmax) {
this.bbox.setFromBoundsArr([vmin.x, vmin.y, vmin.z, vmax.x, vmax.y, vmax.z]);
let x = vmin.x + (vmax.x - vmin.x) * 0.5,
y = vmin.y + (vmax.y - vmin.y) * 0.5,
z = vmin.z + (vmax.z - vmin.z) * 0.5;
this.bsphere.center.set(x, y, z);
this.bsphere.radius = this.bsphere.center.distance(new Vec3(vmin.x, vmin.y, vmin.z));
}
setBoundingVolumeArr(bounds) {
this.bbox.setFromBoundsArr(bounds);
let x = bounds[0] + (bounds[3] - bounds[0]) * 0.5,
y = bounds[1] + (bounds[4] - bounds[1]) * 0.5,
z = bounds[2] + (bounds[5] - bounds[2]) * 0.5;
this.bsphere.center.set(x, y, z);
this.bsphere.radius = this.bsphere.center.distance(
new Vec3(bounds[0], bounds[1], bounds[2])
);
}
createCoordsBuffers(verticesHigh, verticesLow, gridSize) {
var gsgs = (gridSize + 1) * (gridSize + 1);
var h = this.handler;
if (this.vertexPositionBufferHigh && this.vertexPositionBufferHigh.numItems === gsgs) {
h.setStreamArrayBuffer(this.vertexPositionBufferHigh, verticesHigh);
h.setStreamArrayBuffer(this.vertexPositionBufferLow, verticesLow);
} else {
h.gl.deleteBuffer(this.vertexPositionBufferHigh);
h.gl.deleteBuffer(this.vertexPositionBufferLow);
this.vertexTextureCoordBuffer =
this.planet._textureCoordsBufferCache[Math.log2(gridSize)];
//this.vertexPositionBufferHigh = h.createStreamArrayBuffer(3, gsgs);
//h.setStreamArrayBuffer(this.vertexPositionBufferHigh, verticesHigh);
//this.vertexPositionBufferLow = h.createStreamArrayBuffer(3, gsgs);
//h.setStreamArrayBuffer(this.vertexPositionBufferLow, verticesLow);
// It works, but I'm not sure that it is correct and better use the comment above
this.vertexPositionBufferHigh = h.createArrayBuffer(verticesHigh, 3, gsgs);
this.vertexPositionBufferLow = h.createArrayBuffer(verticesLow, 3, gsgs);
}
}
_addViewExtent() {
var ext = this._extentLonLat;
if (!this.planet._viewExtent) {
this.planet._viewExtent = new Extent(
new LonLat(ext.southWest.lon, ext.southWest.lat),
new LonLat(ext.northEast.lon, ext.northEast.lat)
);
return;
}
var viewExt = this.planet._viewExtent;
if (ext.southWest.lon < viewExt.southWest.lon) {
viewExt.southWest.lon = ext.southWest.lon;
}
if (ext.northEast.lon > viewExt.northEast.lon) {
viewExt.northEast.lon = ext.northEast.lon;
}
if (ext.southWest.lat < viewExt.southWest.lat) {
viewExt.southWest.lat = ext.southWest.lat;
}
if (ext.northEast.lat > viewExt.northEast.lat) {
viewExt.northEast.lat = ext.northEast.lat;
}
}
_assignTileIndexes() {
this._tileGroup = 0;
var tileZoom = this.tileZoom;
var extent = this._extent;
var pole = mercator.POLE;
this.tileX = Math.round(
Math.abs(-pole - extent.southWest.lon) / (extent.northEast.lon - extent.southWest.lon)
);
this.tileY = Math.round(
Math.abs(pole - extent.northEast.lat) / (extent.northEast.lat - extent.southWest.lat)
);
var p2 = Math.pow(2, tileZoom);
this.tileXE = (this.tileX + 1) % p2;
this.tileXW = (p2 + this.tileX - 1) % p2;
this.tileYN = this.tileY - 1;
this.tileYS = this.tileY + 1;
this.tileIndex = Layer.getTileIndex(this.tileX, this.tileY, tileZoom);
this.planet._quadTreeNodesCacheMerc[this.tileIndex] = this.node;
}
initialize() {
var p = this.planet;
var n = this.node;
n.sideSize[0] =
n.sideSize[1] =
n.sideSize[2] =
n.sideSize[3] =
this.gridSize =
p.terrain.gridSizeByZoom[this.tileZoom] || p.terrain.plainGridSize;
n.sideSizeLog2[0] =
n.sideSizeLog2[1] =
n.sideSizeLog2[2] =
n.sideSizeLog2[3] =
Math.log2(p.terrain.gridSizeByZoom[this.tileZoom] || p.terrain.plainGridSize);
if (this.tileZoom <= p.terrain.maxZoom) {
var nmc = this.planet._normalMapCreator;
this.normalMapTexturePtr = p.renderer.handler.createEmptyTexture_l(
nmc._width,
nmc._height
);
}
this.normalMapTexture = this.planet.transparentTexture;
this._assignGlobalTextureCoordinates();
this.initialized = true;
}
_assignGlobalTextureCoordinates() {
var e = this._extent;
this._globalTextureCoordinates[0] =
(e.southWest.lon + mercator.POLE) * mercator.ONE_BY_POLE_DOUBLE;
this._globalTextureCoordinates[1] =
(mercator.POLE - e.northEast.lat) * mercator.ONE_BY_POLE_DOUBLE;
this._globalTextureCoordinates[2] =
(e.northEast.lon + mercator.POLE) * mercator.ONE_BY_POLE_DOUBLE;
this._globalTextureCoordinates[3] =
(mercator.POLE - e.southWest.lat) * mercator.ONE_BY_POLE_DOUBLE;
}
createPlainSegmentAsync() {
let p = this.planet,
t = p.terrain;
if (t.isReady() && this.tileZoom <= t.maxZoom && !this.plainReady) {
this.plainProcessing = true;
p._plainSegmentWorker.make(this);
}
}
createPlainSegment() {
this.initialize();
this._createPlainVertices();
this.readyToEngage = true;
}
_createPlainVertices() {
var gridSize = this.planet.terrain.gridSizeByZoom[this.tileZoom];
var e = this._extent,
fgs = this.planet.terrain.plainGridSize;
var lonSize = e.getWidth();
var llStep = lonSize / Math.max(fgs, gridSize);
var esw_lon = e.southWest.lon,
ene_lat = e.northEast.lat;
var dg = Math.max(fgs / gridSize, 1),
gs = Math.max(fgs, gridSize) + 1;
var r2 = this.planet.ellipsoid._invRadii2;
var ind = 0,
nmInd = 0;
const gsgs = gs * gs;
var gridSize3 = (gridSize + 1) * (gridSize + 1) * 3;
this.plainNormals = new Float32Array(gridSize3);
this.plainVertices = new Float64Array(gridSize3);
this.plainVerticesHigh = new Float32Array(gridSize3);
this.plainVerticesLow = new Float32Array(gridSize3);
this.normalMapNormals = new Float32Array(gsgs * 3);
this.normalMapVertices = new Float64Array(gsgs * 3);
this.normalMapVerticesHigh = new Float32Array(gsgs * 3);
this.normalMapVerticesLow = new Float32Array(gsgs * 3);
var verts = this.plainVertices,
vertsHigh = this.plainVerticesHigh,
vertsLow = this.plainVerticesLow,
norms = this.plainNormals,
nmVerts = this.normalMapVertices,
nmVertsHigh = this.normalMapVerticesHigh,
nmVertsLow = this.normalMapVerticesLow,
nmNorms = this.normalMapNormals;
for (let k = 0; k < gsgs; k++) {
var j = k % gs,
i = ~~(k / gs);
var v = this.planet.ellipsoid.lonLatToCartesian(
LonLat.inverseMercator(esw_lon + j * llStep, ene_lat - i * llStep)
);
var nx = v.x * r2.x,
ny = v.y * r2.y,
nz = v.z * r2.z;
var l = 1.0 / Math.sqrt(nx * nx + ny * ny + nz * nz);
var nxl = nx * l,
nyl = ny * l,
nzl = nz * l;
Vec3.doubleToTwoFloats(v, _tempHigh, _tempLow);
nmVerts[nmInd] = v.x;
nmVertsHigh[nmInd] = _tempHigh.x;
nmVertsLow[nmInd] = _tempLow.x;
nmNorms[nmInd++] = nxl;
nmVerts[nmInd] = v.y;
nmVertsHigh[nmInd] = _tempHigh.y;
nmVertsLow[nmInd] = _tempLow.y;
nmNorms[nmInd++] = nyl;
nmVerts[nmInd] = v.z;
nmVertsHigh[nmInd] = _tempHigh.z;
nmVertsLow[nmInd] = _tempLow.z;
nmNorms[nmInd++] = nzl;
if (i % dg === 0 && j % dg === 0) {
verts[ind] = v.x;
vertsHigh[ind] = _tempHigh.x;
vertsLow[ind] = _tempLow.x;
norms[ind++] = nxl;
verts[ind] = v.y;
vertsHigh[ind] = _tempHigh.y;
vertsLow[ind] = _tempLow.y;
norms[ind++] = nyl;
verts[ind] = v.z;
vertsHigh[ind] = _tempHigh.z;
vertsLow[ind] = _tempLow.z;
norms[ind++] = nzl;
}
}
this.terrainVertices = verts;
this.terrainVerticesHigh = vertsHigh;
this.terrainVerticesLow = vertsLow;
this.plainReady = true;
}
/**
* Gets specific layer material.
* @public
* @param {Layer} layer - Layer object.
* @returns {planetSegment.Material} - Segment material.
*/
getMaterialByLayer(layer) {
return this.materials[layer._id];
}
_getLayerExtentOffset(layer) {
var v0s = layer._extentMerc;
var v0t = this._extent;
var sSize_x = v0s.northEast.lon - v0s.southWest.lon;
var sSize_y = v0s.northEast.lat - v0s.southWest.lat;
var dV0s_x = (v0t.southWest.lon - v0s.southWest.lon) / sSize_x;
var dV0s_y = (v0s.northEast.lat - v0t.northEast.lat) / sSize_y;
var dSize_x = (v0t.northEast.lon - v0t.southWest.lon) / sSize_x;
var dSize_y = (v0t.northEast.lat - v0t.southWest.lat) / sSize_y;
return [dV0s_x, dV0s_y, dSize_x, dSize_y];
}
screenRendering(sh, layerSlice, sliceIndex, defaultTexture, isOverlay) {
var gl = this.handler.gl;
var sha = sh.attributes,
shu = sh.uniforms;
var pm = this.materials,
p = this.planet;
var currHeight, li;
if (layerSlice) {
li = layerSlice[0];
currHeight = li._height;
} else {
currHeight = 0;
}
// First always draw whole planet base layer segment with solid texture.
gl.activeTexture(gl.TEXTURE0 + p.SLICE_SIZE + 2);
gl.bindTexture(gl.TEXTURE_2D, defaultTexture || this.getDefaultTexture());
gl.uniform1i(shu.defaultTexture, p.SLICE_SIZE + 2);
var n = 0,
i = 0;
var notEmpty = false;
var slice = this._renderingSlices[sliceIndex];
if (!slice) {
slice = this._renderingSlices[sliceIndex] = new _RenderingSlice(p);
} else {
slice.layers = [];
}
this._indexBuffer = this._getIndexBuffer();
while (li) {
if (
this.layerOverlap(li) &&
((li._fading && li._fadingOpacity > 0.0) ||
((li.minZoom >= p.minCurrZoom || li.maxZoom >= p.minCurrZoom) &&
(li.minZoom <= p.maxCurrZoom || li.maxZoom <= p.maxCurrZoom)))
) {
notEmpty = true;
var m = pm[li._id];
if (!m) {
m = pm[li._id] = li.createMaterial(this);
}
if (!m.isReady) {
this.planet._renderCompleted = false;
}
slice.layers.push(li);
var n4 = n * 4;
var arr = li.applyMaterial(m);
slice.tileOffsetArr[n4] = arr[0];
slice.tileOffsetArr[n4 + 1] = arr[1];
slice.tileOffsetArr[n4 + 2] = arr[2];
slice.tileOffsetArr[n4 + 3] = arr[3];
arr = this._getLayerExtentOffset(li);
slice.visibleExtentOffsetArr[n4] = arr[0];
slice.visibleExtentOffsetArr[n4 + 1] = arr[1];
slice.visibleExtentOffsetArr[n4 + 2] = arr[2];
slice.visibleExtentOffsetArr[n4 + 3] = arr[3];
slice.layerOpacityArr[n] = li.opacity;
p._samplerArr[n] = n;
gl.activeTexture(gl.TEXTURE0 + n);
gl.bindTexture(gl.TEXTURE_2D, m.texture || p.transparentTexture);
n++;
}
i++;
li = layerSlice[i];
}
if (notEmpty || !isOverlay) {
gl.uniform1i(shu.samplerCount, n);
gl.uniform1f(shu.height, currHeight);
gl.uniform1iv(shu.samplerArr, p._samplerArr);
gl.uniform4fv(shu.tileOffsetArr, slice.tileOffsetArr);
gl.uniform4fv(shu.visibleExtentOffsetArr, slice.visibleExtentOffsetArr);
gl.uniform1fv(shu.layerOpacityArr, slice.layerOpacityArr);
// bind normalmap texture
if (p.lightEnabled) {
gl.activeTexture(gl.TEXTURE0 + p.SLICE_SIZE + 3);
gl.bindTexture(gl.TEXTURE_2D, this.normalMapTexture || p.transparentTexture);
gl.uniform1i(shu.uNormalMap, p.SLICE_SIZE + 3);
gl.uniform3fv(shu.uNormalMapBias, this.normalMapTextureBias);
// bind segment specular and night material texture coordinates
gl.uniform4fv(shu.uGlobalTextureCoord, this._globalTextureCoordinates);
}
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBufferHigh);
gl.vertexAttribPointer(
sha.aVertexPositionHigh,
this.vertexPositionBufferHigh.itemSize,
gl.FLOAT,
false,
0,
0
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBufferLow);
gl.vertexAttribPointer(
sha.aVertexPositionLow,
this.vertexPositionBufferLow.itemSize,
gl.FLOAT,
false,
0,
0
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexTextureCoordBuffer);
gl.vertexAttribPointer(sha.aTextureCoord, 2, gl.UNSIGNED_SHORT, true, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
gl.drawElements(p.drawMode, this._indexBuffer.numItems, gl.UNSIGNED_INT, 0);
}
}
heightPickingRendering(sh, layerSlice, sliceIndex, defaultTexture, isOverlay) {
var gl = this.handler.gl;
var sha = sh.attributes,
shu = sh.uniforms;
var pm = this.materials,
p = this.planet;
// First always draw whole planet base layer segment with solid texture.
gl.activeTexture(gl.TEXTURE0 + p.SLICE_SIZE);
gl.bindTexture(gl.TEXTURE_2D, defaultTexture || p.solidTextureOne);
gl.uniform1i(shu.defaultTexture, p.SLICE_SIZE);
var currHeight;
if (layerSlice) {
currHeight = layerSlice[0]._height;
} else {
currHeight = 0;
}
var n = 0;
var slice = this._renderingSlices[sliceIndex];
var notEmpty = false;
for (n = 0; n < slice.layers.length; n++) {
notEmpty = true;
p._samplerArr[n] = n;
gl.activeTexture(gl.TEXTURE0 + n);
gl.bindTexture(gl.TEXTURE_2D, pm[slice.layers[n]._id].texture || p.transparentTexture);
}
if (notEmpty || !isOverlay) {
gl.uniform1i(shu.samplerCount, n);
gl.uniform1f(shu.height, currHeight);
gl.uniform1iv(shu.samplerArr, p._samplerArr);
gl.uniform4fv(shu.tileOffsetArr, slice.tileOffsetArr);
gl.uniform4fv(shu.visibleExtentOffsetArr, slice.visibleExtentOffsetArr);
gl.uniform1fv(shu.layerOpacityArr, slice.layerOpacityArr);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBufferHigh);
gl.vertexAttribPointer(
sha.aVertexPositionHigh,
this.vertexPositionBufferHigh.itemSize,
gl.FLOAT,
false,
0,
0
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBufferLow);
gl.vertexAttribPointer(
sha.aVertexPositionLow,
this.vertexPositionBufferLow.itemSize,
gl.FLOAT,
false,
0,
0
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexTextureCoordBuffer);
gl.vertexAttribPointer(sha.aTextureCoord, 2, gl.UNSIGNED_SHORT, true, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
gl.drawElements(gl.TRIANGLE_STRIP, this._indexBuffer.numItems, gl.UNSIGNED_INT, 0);
}
}
colorPickingRendering(sh, layerSlice, sliceIndex, defaultTexture, isOverlay) {
var gl = this.handler.gl;
var sha = sh.attributes,
shu = sh.uniforms;
var pm = this.materials,
p = this.planet;
var currHeight;
if (layerSlice) {
currHeight = layerSlice[0]._height;
} else {
currHeight = 0;
}
var notEmpty = false;
var slice = this._renderingSlices[sliceIndex];
for (var n = 0; n < slice.layers.length; n++) {
notEmpty = true;
var li = slice.layers[n];
var n4 = n * 4;
p._pickingColorArr[n4] = li._pickingColor.x / 255.0;
p._pickingColorArr[n4 + 1] = li._pickingColor.y / 255.0;
p._pickingColorArr[n4 + 2] = li._pickingColor.z / 255.0;
p._pickingColorArr[n4 + 3] = li._pickingEnabled;
p._samplerArr[n] = n;
gl.activeTexture(gl.TEXTURE0 + n);
gl.bindTexture(gl.TEXTURE_2D, pm[li._id].texture || this.planet.transparentTexture);
p._pickingMaskArr[n] = n + p.SLICE_SIZE;
gl.activeTexture(gl.TEXTURE0 + n + p.SLICE_SIZE);
gl.bindTexture(gl.TEXTURE_2D, pm[li._id].pickingMask || this.planet.transparentTexture);
}
if (notEmpty || !isOverlay) {
gl.uniform1i(shu.samplerCount, n);
gl.uniform1f(shu.height, currHeight);
gl.uniform1iv(shu.samplerArr, p._samplerArr);
gl.uniform1iv(shu.pickingMaskArr, p._pickingMaskArr);
gl.uniform4fv(shu.tileOffsetArr, slice.tileOffsetArr);
gl.uniform4fv(shu.visibleExtentOffsetArr, slice.visibleExtentOffsetArr);
gl.uniform1fv(shu.layerOpacityArr, slice.layerOpacityArr);
gl.uniform4fv(shu.pickingColorArr, p._pickingColorArr);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBufferHigh);
gl.vertexAttribPointer(
sha.aVertexPositionHigh,
this.vertexPositionBufferHigh.itemSize,
gl.FLOAT,
false,
0,
0
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBufferLow);
gl.vertexAttribPointer(
sha.aVertexPositionLow,
this.vertexPositionBufferLow.itemSize,
gl.FLOAT,
false,
0,
0
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexTextureCoordBuffer);
gl.vertexAttribPointer(sha.aTextureCoord, 2, gl.UNSIGNED_SHORT, true, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
gl.drawElements(gl.TRIANGLE_STRIP, this._indexBuffer.numItems, gl.UNSIGNED_INT, 0);
}
}
depthRendering(sh, layerSlice, sliceIndex, defaultTexture, isOverlay) {
var gl = this.handler.gl;
var sha = sh.attributes,
shu = sh.uniforms;
var pm = this.materials,
p = this.planet;
// First always draw whole planet base layer segment with solid texture.
gl.activeTexture(gl.TEXTURE0 + p.SLICE_SIZE);
gl.bindTexture(gl.TEXTURE_2D, defaultTexture || p.solidTextureOne);
gl.uniform1i(shu.defaultTexture, p.SLICE_SIZE);
var currHeight;
if (layerSlice) {
currHeight = layerSlice[0]._height;
} else {
currHeight = 0;
}
var n = 0;
var slice = this._renderingSlices[sliceIndex];
var notEmpty = false;
for (n = 0; n < slice.layers.length; n++) {
notEmpty = true;
p._samplerArr[n] = n;
gl.activeTexture(gl.TEXTURE0 + n);
gl.bindTexture(gl.TEXTURE_2D, pm[slice.layers[n]._id].texture || p.transparentTexture);
}
if (notEmpty || !isOverlay) {
gl.uniform1i(shu.samplerCount, n);
gl.uniform1f(shu.height, currHeight);
gl.uniform1iv(shu.samplerArr, p._samplerArr);
gl.uniform4fv(shu.tileOffsetArr, slice.tileOffsetArr);
gl.uniform4fv(shu.visibleExtentOffsetArr, slice.visibleExtentOffsetArr);
gl.uniform1fv(shu.layerOpacityArr, slice.layerOpacityArr);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBufferHigh);
gl.vertexAttribPointer(
sha.aVertexPositionHigh,
this.vertexPositionBufferHigh.itemSize,
gl.FLOAT,
false,
0,
0
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexPositionBufferLow);
gl.vertexAttribPointer(
sha.aVertexPositionLow,
this.vertexPositionBufferLow.itemSize,
gl.FLOAT,
false,
0,
0
);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexTextureCoordBuffer);
gl.vertexAttribPointer(sha.aTextureCoord, 2, gl.UNSIGNED_SHORT, true, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
gl.drawElements(gl.TRIANGLE_STRIP, this._indexBuffer.numItems, gl.UNSIGNED_INT, 0);
}
}
_getIndexBuffer() {
var s = this.node.sideSizeLog2;
var cache = this.planet._indexesCache[Math.log2(this.gridSize)][s[0]][s[1]][s[2]][s[3]];
if (!cache.buffer) {
let indexes = segmentHelper
.getInstance()
.createSegmentIndexes(Math.log2(this.gridSize), [s[0], s[1], s[2], s[3]]);
cache.buffer = this.planet.renderer.handler.createElementArrayBuffer(indexes, 1);
this.planet._indexesCacheToRemoveCounter++;
indexes = null;
}
return cache.buffer;
}
_collectVisibleNodes() {
this.planet._visibleNodes[this.node.nodeId] = this.node;
}
layerOverlap(layer) {
return this._extent.overlaps(layer._extentMerc);
}
getDefaultTexture() {
return this.planet.solidTextureOne;
}
getExtentLonLat() {
return this._extentLonLat;
}
getExtentMerc() {
return this._extent;
}
getExtent() {
return this._extent;
}
getNodeState() {
var vn = this.planet._visibleNodes[this.node.nodeId];
return (vn && vn.state) || NOTRENDERING;
}
getNeighborSide(b) {
if (this.tileY === b.tileY) {
if (this.tileX === b.tileXE) {
return W;
} else if (this.tileX === b.tileXW) {
return E;
}
} else if (this.tileX === b.tileX) {
if (this.tileY === b.tileYS) {
return N;
} else if (this.tileY === b.tileYN) {
return S;
}
}
return -1;
}
}
export { Segment };