| @@ -0,0 +1,67 @@ | |||
| /** | |||
| * @Author: Caven | |||
| * @Date: 2021-03-14 00:41:29 | |||
| */ | |||
| 'use strict' | |||
| const path = require('path') | |||
| const webpack = require('webpack') | |||
| const JavaScriptObfuscator = require('webpack-obfuscator') | |||
| const common = require('./common') | |||
| module.exports = env => { | |||
| const IS_PROD = (env && env.production) || false | |||
| const publicPath = IS_PROD ? '/' : '/' | |||
| let plugins = [...common.plugins] | |||
| if (IS_PROD) { | |||
| plugins.push(new webpack.NoEmitOnErrorsPlugin()) | |||
| plugins.push( | |||
| new JavaScriptObfuscator( | |||
| { | |||
| rotateStringArray: true | |||
| }, | |||
| [] | |||
| ) | |||
| ) | |||
| } | |||
| return { | |||
| entry: { | |||
| 'dc.s3m': ['entry'] | |||
| }, | |||
| devtool: IS_PROD ? false : 'cheap-module-eval-source-map', | |||
| output: { | |||
| filename: IS_PROD ? '[name].min.js' : '[name].js', | |||
| path: path.resolve(__dirname, '..', 'packages/s3m/dist'), | |||
| publicPath: publicPath, | |||
| library: 'DcS3M', | |||
| libraryExport: 'default', | |||
| libraryTarget: 'umd', | |||
| umdNamedDefine: true | |||
| }, | |||
| module: { | |||
| unknownContextCritical: false, | |||
| rules: [ | |||
| { | |||
| test: /\.js$/, | |||
| exclude: /node_modules/, | |||
| loader: 'babel-loader', | |||
| options: { | |||
| presets: ['@babel/preset-env'], | |||
| compact: false, | |||
| ignore: ['checkTree'] | |||
| } | |||
| } | |||
| ] | |||
| }, | |||
| resolve: { | |||
| extensions: ['.js', '.json', '.css'], | |||
| alias: { | |||
| '@dc-modules': path.resolve(__dirname, '..', 'modules'), | |||
| 's3m-lib': path.resolve(__dirname, '..', 'libs/s3m'), | |||
| entry: path.resolve(__dirname, '..', 'packages/s3m/index.js') | |||
| } | |||
| }, | |||
| plugins | |||
| } | |||
| } | |||
| @@ -0,0 +1,286 @@ | |||
| //! Use DXT1 compression. | |||
| var kDxt1 = 1 << 0 | |||
| //! Use DXT3 compression. | |||
| var kDxt3 = 1 << 1 | |||
| //! Use DXT5 compression. | |||
| var kDxt5 = 1 << 2 | |||
| //! Use a very slow but very high quality colour compressor. | |||
| var kColourIterativeClusterFit = 1 << 8 | |||
| //! Use a slow but high quality colour compressor (the default). | |||
| var kColourClusterFit = 1 << 3 | |||
| //! Use a fast but low quality colour compressor. | |||
| var kColourRangeFit = 1 << 4 | |||
| //! Weight the colour by alpha during cluster fit (disabled by default). | |||
| var kWeightColourByAlpha = 1 << 7 | |||
| var krgb565 = 1 << 5 | |||
| function Unpack565(packed0, packed1, colour, offset) { | |||
| var value = packed0 | (packed1 << 8) | |||
| var red = (value >> 11) & 0x1f | |||
| var green = (value >> 5) & 0x3f | |||
| var blue = value & 0x1f | |||
| colour[offset + 0] = (red << 3) | (red >> 2) | |||
| colour[offset + 1] = (green << 2) | (green >> 4) | |||
| colour[offset + 2] = (blue << 3) | (blue >> 2) | |||
| colour[offset + 3] = 255 | |||
| return value | |||
| } | |||
| function DecompressColour(rgba, block, nOffset, isDxt1) { | |||
| var codes = new Uint8Array(16) | |||
| var a = Unpack565(block[nOffset + 0], block[nOffset + 1], codes, 0) | |||
| var b = Unpack565(block[nOffset + 2], block[nOffset + 3], codes, 4) | |||
| for (var i = 0; i < 3; i++) { | |||
| var c = codes[i] | |||
| var d = codes[4 + i] | |||
| if (isDxt1 && a <= b) { | |||
| codes[8 + i] = (c + d) / 2 | |||
| codes[12 + i] = 0 | |||
| } else { | |||
| codes[8 + i] = (2 * c + d) / 3 | |||
| codes[12 + i] = (c + 2 * d) / 3 | |||
| } | |||
| } | |||
| codes[8 + 3] = 255 | |||
| codes[12 + 3] = isDxt1 && a <= b ? 0 : 255 | |||
| var indices = new Uint8Array(16) | |||
| for (var i = 0; i < 4; ++i) { | |||
| var packed = block[nOffset + 4 + i] | |||
| indices[4 * i + 0] = packed & 0x3 | |||
| indices[4 * i + 1] = (packed >> 2) & 0x3 | |||
| indices[4 * i + 2] = (packed >> 4) & 0x3 | |||
| indices[4 * i + 3] = (packed >> 6) & 0x3 | |||
| } | |||
| for (var i = 0; i < 16; ++i) { | |||
| var offset = 4 * indices[i] | |||
| for (var j = 0; j < 4; ++j) rgba[4 * i + j] = codes[offset + j] | |||
| } | |||
| } | |||
| function DecompressAlphaDxt3(rgba, block, nOffset) { | |||
| // unpack the alpha values pairwise | |||
| for (var i = 0; i < 8; ++i) { | |||
| // quantise down to 4 bits | |||
| var quant = bytes[nOffset + i] | |||
| // unpack the values | |||
| var lo = quant & 0x0f | |||
| var hi = quant & 0xf0 | |||
| // convert back up to bytes | |||
| rgba[8 * i + 3] = lo | (lo << 4) | |||
| rgba[8 * i + 7] = hi | (hi >> 4) | |||
| } | |||
| } | |||
| function DecompressAlphaDxt5(rgba, block, nOffset) { | |||
| var alpha0 = block[nOffset + 0] | |||
| var alpha1 = block[nOffset + 1] | |||
| var codes = new Uint8Array(8) | |||
| codes[0] = alpha0 | |||
| codes[1] = alpha1 | |||
| if (alpha0 <= alpha1) { | |||
| // use 5-alpha codebook | |||
| for (var i = 1; i < 5; ++i) | |||
| codes[1 + i] = ((5 - i) * alpha0 + i * alpha1) / 5 | |||
| codes[6] = 0 | |||
| codes[7] = 255 | |||
| } else { | |||
| // use 7-alpha codebook | |||
| for (var i = 1; i < 7; ++i) | |||
| codes[1 + i] = ((7 - i) * alpha0 + i * alpha1) / 7 | |||
| } | |||
| var indices = new Uint8Array(16) | |||
| var nOffset = nOffset + 2 | |||
| var nBegin = 0 | |||
| for (var i = 0; i < 2; ++i) { | |||
| // grab 3 bytes | |||
| var value = 0 | |||
| for (var j = 0; j < 3; ++j) { | |||
| var byte = block[nOffset++] | |||
| value |= byte << (8 * j) | |||
| } | |||
| // unpack 8 3-bit values from it | |||
| for (var j = 0; j < 8; ++j) { | |||
| var index = (value >> (3 * j)) & 0x7 | |||
| indices[nBegin++] = index | |||
| } | |||
| } | |||
| for (var i = 0; i < 16; ++i) rgba[4 * i + 3] = codes[indices[i]] | |||
| } | |||
| function Decompress(rgba, block, nOffset, flags) { | |||
| var nOffset2 = 0 | |||
| if ((flags & (kDxt3 | kDxt5)) != 0) nOffset2 = 8 | |||
| DecompressColour(rgba, block, nOffset + nOffset2, (flags & kDxt1) != 0) | |||
| if ((flags & kDxt3) != 0) { | |||
| DecompressAlphaDxt3(rgba, block, nOffset) | |||
| } else if ((flags & kDxt5) != 0) { | |||
| DecompressAlphaDxt5(rgba, block, nOffset) | |||
| } | |||
| } | |||
| function DecompressImage565(rgb565, width, height, blocks) { | |||
| var c = new Uint16Array(4) | |||
| var dst = rgb565 | |||
| var m = 0 | |||
| var dstI = 0 | |||
| var i = 0 | |||
| var r0 = 0, | |||
| g0 = 0, | |||
| b0 = 0, | |||
| r1 = 0, | |||
| g1 = 0, | |||
| b1 = 0 | |||
| var blockWidth = width / 4 | |||
| var blockHeight = height / 4 | |||
| for (var blockY = 0; blockY < blockHeight; blockY++) { | |||
| for (var blockX = 0; blockX < blockWidth; blockX++) { | |||
| i = 4 * ((blockHeight - blockY) * blockWidth + blockX) | |||
| c[0] = blocks[i] | |||
| c[1] = blocks[i + 1] | |||
| r0 = c[0] & 0x1f | |||
| g0 = c[0] & 0x7e0 | |||
| b0 = c[0] & 0xf800 | |||
| r1 = c[1] & 0x1f | |||
| g1 = c[1] & 0x7e0 | |||
| b1 = c[1] & 0xf800 | |||
| // Interpolate between c0 and c1 to get c2 and c3. ~ | |||
| // Note that we approximate 1/3 as 3/8 and 2/3 as 5/8 for | |||
| // speed. This also appears to be what the hardware DXT | |||
| // decoder in many GPUs does :) | |||
| c[2] = | |||
| ((5 * r0 + 3 * r1) >> 3) | | |||
| (((5 * g0 + 3 * g1) >> 3) & 0x7e0) | | |||
| (((5 * b0 + 3 * b1) >> 3) & 0xf800) | |||
| c[3] = | |||
| ((5 * r1 + 3 * r0) >> 3) | | |||
| (((5 * g1 + 3 * g0) >> 3) & 0x7e0) | | |||
| (((5 * b1 + 3 * b0) >> 3) & 0xf800) | |||
| m = blocks[i + 2] | |||
| dstI = blockY * 4 * width + blockX * 4 | |||
| dst[dstI] = c[m & 0x3] | |||
| dst[dstI + 1] = c[(m >> 2) & 0x3] | |||
| dst[dstI + 2] = c[(m >> 4) & 0x3] | |||
| dst[dstI + 3] = c[(m >> 6) & 0x3] | |||
| dstI += width | |||
| dst[dstI] = c[(m >> 8) & 0x3] | |||
| dst[dstI + 1] = c[(m >> 10) & 0x3] | |||
| dst[dstI + 2] = c[(m >> 12) & 0x3] | |||
| dst[dstI + 3] = c[m >> 14] | |||
| m = blocks[i + 3] | |||
| dstI += width | |||
| dst[dstI] = c[m & 0x3] | |||
| dst[dstI + 1] = c[(m >> 2) & 0x3] | |||
| dst[dstI + 2] = c[(m >> 4) & 0x3] | |||
| dst[dstI + 3] = c[(m >> 6) & 0x3] | |||
| dstI += width | |||
| dst[dstI] = c[(m >> 8) & 0x3] | |||
| dst[dstI + 1] = c[(m >> 10) & 0x3] | |||
| dst[dstI + 2] = c[(m >> 12) & 0x3] | |||
| dst[dstI + 3] = c[m >> 14] | |||
| } | |||
| } | |||
| return dst | |||
| } | |||
| /*! @brief Decompresses an image in memory. | |||
| @param rgba Storage for the decompressed pixels. | |||
| @param width The width of the source image. | |||
| @param height The height of the source image. | |||
| @param blocks The compressed DXT blocks. | |||
| @param flags Compression flags. | |||
| The decompressed pixels will be written as a contiguous array of width*height | |||
| 16 rgba values, with each component as 1 byte each. In memory this is: | |||
| { r1, g1, b1, a1, .... , rn, gn, bn, an } for n = width*height | |||
| The flags parameter should specify either kDxt1, kDxt3 or kDxt5 compression, | |||
| however, DXT1 will be used by default if none is specified. All other flags | |||
| are ignored. | |||
| Internally this function calls squish::Decompress for each block. | |||
| */ | |||
| function DecompressImage(rgba, width, height, blocks, flags) { | |||
| var bytesPerBlock = (flags & kDxt1) != 0 ? 8 : 16 | |||
| var nOffset = 0 | |||
| for (var y = 0; y < height; y += 4) { | |||
| for (var x = 0; x < width; x += 4) { | |||
| var targetRgba = new Uint8Array(4 * 16) | |||
| Decompress(targetRgba, blocks, nOffset, flags) | |||
| var nOffsetTarget = 0 | |||
| for (var py = 0; py < 4; ++py) { | |||
| for (var px = 0; px < 4; ++px) { | |||
| var sx = x + px | |||
| var sy = y + py | |||
| if (sx < width && sy < height) { | |||
| // flip Y | |||
| var nBegin = 4 * (width * (height - sy) + sx) | |||
| for (var i = 0; i < 4; ++i) { | |||
| rgba[nBegin++] = targetRgba[nOffsetTarget++] | |||
| } | |||
| } else { | |||
| nOffsetTarget += 4 | |||
| } | |||
| } | |||
| } | |||
| // advance | |||
| nOffset += bytesPerBlock | |||
| } | |||
| } | |||
| } | |||
| function DXTTextureDecode(options) {} | |||
| DXTTextureDecode.decode = function(out, width, height, block, format) { | |||
| if (out == null || block == null || height == 0 || width == 0) { | |||
| return | |||
| } | |||
| var flags = 0 | |||
| //有alpha通道,转为RGBA,否则转为rgb565 | |||
| // S3MPixelFormat.BGR -> 11 | |||
| //S3MPixelFormat.LUMINANCE_ALPHA -> 5 | |||
| if (format > 11 || format === 5) { | |||
| flags = kDxt5 | |||
| } else { | |||
| flags = kDxt1 | krgb565 | |||
| } | |||
| if (flags & kDxt1 && flags & krgb565) { | |||
| DecompressImage565(out, width, height, block) | |||
| } else { | |||
| DecompressImage(out, width, height, block, flags) | |||
| } | |||
| } | |||
| export default DXTTextureDecode | |||
| @@ -0,0 +1,162 @@ | |||
| const NOCOMPRESSED_RGB565 = 0x111 | |||
| const NOCOMPRESSED_RGBA = 0x1111 | |||
| const NOCOMPRESSED_LA = 6410 | |||
| const { Cesium } = DC.Namespace | |||
| function DDSTexture(context, id, options) { | |||
| let gl = context._gl | |||
| this.contextId = context.id | |||
| this.textureId = id | |||
| this.layerId = options.layerId | |||
| this.rootName = options.rootName | |||
| this.context = context | |||
| this.width = options.width | |||
| this.height = options.height | |||
| this.compressType = options.compressType | |||
| this.internalFormat = options.internalFormat | |||
| this.pixelFormat = options.pixelFormat | |||
| this.arrayBufferView = options.arrayBufferView | |||
| this.wrapS = Cesium.defaultValue( | |||
| options.wrapS, | |||
| Cesium.TextureWrap.CLAMP_TO_EDGE | |||
| ) | |||
| this.wrapT = Cesium.defaultValue( | |||
| options.wrapT, | |||
| Cesium.TextureWrap.CLAMP_TO_EDGE | |||
| ) | |||
| this._target = gl.TEXTURE_2D | |||
| this._texture = undefined | |||
| this.refCount = 1 | |||
| if (this.arrayBufferView) { | |||
| this.init() | |||
| } | |||
| } | |||
| DDSTexture.prototype.init = function() { | |||
| let gl = this.context._gl | |||
| if (!this._texture) { | |||
| this._texture = gl.createTexture() | |||
| } | |||
| gl.bindTexture(gl.TEXTURE_2D, this._texture) | |||
| let internalFormat = this.internalFormat | |||
| if ( | |||
| internalFormat === NOCOMPRESSED_LA || | |||
| internalFormat === NOCOMPRESSED_RGBA | |||
| ) { | |||
| gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true) | |||
| } | |||
| let i = 0 | |||
| let offset = 0 | |||
| let texWidth = this.width | |||
| let texHeight = this.height | |||
| let bMipMap = validateMipmap( | |||
| this.arrayBufferView, | |||
| internalFormat, | |||
| texWidth, | |||
| texHeight | |||
| ) | |||
| do { | |||
| let levelSize = Cesium.PixelFormat.compressedTextureSizeInBytes( | |||
| internalFormat, | |||
| texWidth, | |||
| texHeight | |||
| ) | |||
| let subArrayBuffer = new Uint8Array( | |||
| this.arrayBufferView.buffer, | |||
| this.arrayBufferView.byteOffset + offset, | |||
| levelSize | |||
| ) | |||
| if (internalFormat === NOCOMPRESSED_RGBA) { | |||
| gl.texImage2D( | |||
| gl.TEXTURE_2D, | |||
| i++, | |||
| gl.RGBA, | |||
| texWidth, | |||
| texHeight, | |||
| 0, | |||
| gl.RGBA, | |||
| gl.UNSIGNED_BYTE, | |||
| subArrayBuffer | |||
| ) | |||
| } else { | |||
| gl.compressedTexImage2D( | |||
| gl.TEXTURE_2D, | |||
| i++, | |||
| internalFormat, | |||
| texWidth, | |||
| texHeight, | |||
| 0, | |||
| subArrayBuffer | |||
| ) | |||
| } | |||
| texWidth = Math.max(texWidth >> 1, 1) | |||
| texHeight = Math.max(texHeight >> 1, 1) | |||
| offset += levelSize | |||
| } while (offset < this.arrayBufferView.byteLength && bMipMap) | |||
| if (i > 1) { | |||
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) | |||
| gl.texParameteri( | |||
| gl.TEXTURE_2D, | |||
| gl.TEXTURE_MIN_FILTER, | |||
| gl.LINEAR_MIPMAP_LINEAR | |||
| ) | |||
| } else { | |||
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) | |||
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) | |||
| } | |||
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, this.wrapS) | |||
| gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, this.wrapT) | |||
| gl.texParameteri( | |||
| this._target, | |||
| this.context._textureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, | |||
| 1 | |||
| ) | |||
| gl.bindTexture(gl.TEXTURE_2D, null) | |||
| this.arrayBufferView = undefined | |||
| this.ready = true | |||
| } | |||
| function validateMipmap(buffer, pixelFormat, width, height) { | |||
| let len = buffer.length | |||
| let w = width, | |||
| h = height | |||
| let totalBytes = 0 | |||
| while (1) { | |||
| let sizeInBytes = Cesium.PixelFormat.compressedTextureSizeInBytes( | |||
| pixelFormat, | |||
| w, | |||
| h | |||
| ) | |||
| totalBytes += sizeInBytes | |||
| w = w >> 1 | |||
| h = h >> 1 | |||
| if (w === 0 && h === 0) { | |||
| break | |||
| } | |||
| w = Math.max(w, 1) | |||
| h = Math.max(h, 1) | |||
| } | |||
| return totalBytes === len | |||
| } | |||
| DDSTexture.prototype.isDestroyed = function() { | |||
| return false | |||
| } | |||
| DDSTexture.prototype.destroy = function() { | |||
| let gl = this.context._gl | |||
| gl.deleteTexture(this._texture) | |||
| this._texture = null | |||
| this.id = 0 | |||
| Cesium.destroyObject(this) | |||
| } | |||
| export default DDSTexture | |||
| @@ -0,0 +1,9 @@ | |||
| const ContentState = { | |||
| UNLOADED: 0, | |||
| LOADING: 1, | |||
| PARSING: 2, | |||
| READY: 3, | |||
| FAILED: 4 | |||
| } | |||
| export default Object.freeze(ContentState) | |||
| @@ -0,0 +1,5 @@ | |||
| const InstanceMode = { | |||
| BIM: 17 | |||
| } | |||
| export default Object.freeze(InstanceMode) | |||
| @@ -0,0 +1,12 @@ | |||
| const OperationType = { | |||
| RESET: 0, | |||
| SetColor: 0x01, | |||
| SELECTED: 0x02, | |||
| HIDE: 0x04, | |||
| OFFSET: 0x08, | |||
| CLIP: 0x10, | |||
| BLOOM: 0x20, | |||
| ALL: 0xff | |||
| } | |||
| export default Object.freeze(OperationType) | |||
| @@ -0,0 +1,16 @@ | |||
| const ProgramDefines = { | |||
| VertexNormal: 'VertexNormal', | |||
| VertexColor: 'VertexColor', | |||
| TexCoord: 'TexCoord', | |||
| TexCoord2: 'TexCoord2', | |||
| Instance: 'Instance', | |||
| COMPRESS_VERTEX: 'COMPRESS_VERTEX', | |||
| COMPRESS_NORMAL: 'COMPRESS_NORMAL', | |||
| COMPRESS_COLOR: 'COMPRESS_COLOR', | |||
| COMPRESS_TEXCOORD: 'COMPRESS_TEXCOORD', | |||
| UseLineColor: 'USE_LINECOLOR', | |||
| InstanceBim: 'InstanceBim', | |||
| COMPUTE_TEXCOORD: 'COMPUTE_TEXCOORD' | |||
| } | |||
| export default Object.freeze(ProgramDefines) | |||
| @@ -0,0 +1,6 @@ | |||
| const RangeMode = { | |||
| Distance: 0, | |||
| Pixel: 1 | |||
| } | |||
| export default Object.freeze(RangeMode) | |||
| @@ -0,0 +1,9 @@ | |||
| const S3MCompressType = { | |||
| encNONE: 0, | |||
| enrS3TCDXTN: 14, | |||
| enrPVRTPF_PVRTC2: 19, | |||
| enrPVRTPF_PVRTC: 20, | |||
| enrPVRTPF_PVRTC_4bpp: 21, | |||
| enrPVRTPF_ETC1: 22 | |||
| } | |||
| export default S3MCompressType | |||
| @@ -0,0 +1,24 @@ | |||
| const S3MPixelFormat = { | |||
| LUMINANCE_8: 1, | |||
| LUMINANCE_16: 2, | |||
| ALPHA: 3, | |||
| ALPHA_4_LUMINANCE_4: 4, | |||
| LUMINANCE_ALPHA: 5, | |||
| RGB_565: 6, | |||
| BGR565: 7, | |||
| RGB: 10, | |||
| BGR: 11, | |||
| ARGB: 12, | |||
| ABGR: 13, | |||
| BGRA: 14, | |||
| WEBP: 25, | |||
| RGBA: 28, | |||
| DXT1: 17, | |||
| DXT2: 18, | |||
| DXT3: 19, | |||
| DXT4: 20, | |||
| DXT5: 21, | |||
| CRN_DXT5: 26, | |||
| STANDARD_CRN: 27 | |||
| } | |||
| export default Object.freeze(S3MPixelFormat) | |||
| @@ -0,0 +1,9 @@ | |||
| const VertexCompressOptions = { | |||
| SVC_Vertex: 1, | |||
| SVC_Normal: 2, | |||
| SVC_VertexColor: 4, | |||
| SVC_SecondColor: 8, | |||
| SVC_TexutreCoord: 16, | |||
| SVC_TexutreCoordIsW: 32 | |||
| } | |||
| export default Object.freeze(VertexCompressOptions) | |||
| @@ -0,0 +1,309 @@ | |||
| import S3MCreateVertexJob from '../S3MCreateVertexJob.js' | |||
| import S3MCreateIndexJob from '../S3MCreateIndexJob.js' | |||
| import S3MCreateShaderProgramJob from '../S3MCreateShaderProgramJob.js' | |||
| import MaterialPass from '../MaterialPass.js' | |||
| const { Cesium } = DC.Namespace | |||
| function RenderEntity(options) { | |||
| this.layer = options.layer | |||
| this.vertexPackage = options.vertexPackage | |||
| this.arrIndexPackage = options.arrIndexPackage | |||
| this.vertexBufferToCreate = new Cesium.Queue() | |||
| this.indexBufferToCreate = new Cesium.Queue() | |||
| this.shaderProgramToCreate = new Cesium.Queue() | |||
| let i, j | |||
| for (i = 0, j = this.vertexPackage.vertexAttributes.length; i < j; i++) { | |||
| this.vertexBufferToCreate.enqueue(i) | |||
| } | |||
| for (i = 0, j = this.arrIndexPackage.length; i < j; i++) { | |||
| this.indexBufferToCreate.enqueue(i) | |||
| } | |||
| this.shaderProgramToCreate.enqueue(0) | |||
| this.boundingVolume = options.boundingVolume | |||
| this.material = Cesium.defaultValue(options.material, new MaterialPass()) | |||
| this.geoName = options.geoName | |||
| this.modelMatrix = options.modelMatrix | |||
| this.geoMatrix = options.geoMatrix | |||
| this.invGeoMatrix = Cesium.Matrix4.inverse( | |||
| this.geoMatrix, | |||
| new Cesium.Matrix4() | |||
| ) | |||
| this.instanceCount = options.vertexPackage.instanceCount | |||
| this.attributeLocations = options.vertexPackage.attrLocation | |||
| this.shaderProgram = undefined | |||
| this.vertexArray = undefined | |||
| this.colorCommand = undefined | |||
| this.pickInfo = Cesium.defaultValue(options.pickInfo, {}) | |||
| this.selectionInfoMap = new Cesium.AssociativeArray() | |||
| this.batchTable = undefined | |||
| this.batchTableDirty = false | |||
| this.idsOperationMap = new Cesium.AssociativeArray() | |||
| this.pickColorIdentifier = 'vSecondColor' | |||
| this.createBoundingBoxForInstance() | |||
| this.ready = false | |||
| } | |||
| const _vertexBufferJob = new S3MCreateVertexJob() | |||
| const _indexBufferJob = new S3MCreateIndexJob() | |||
| const _shaderProgramJob = new S3MCreateShaderProgramJob() | |||
| function createVertexBuffers(renderEntity, frameState) { | |||
| let context = renderEntity.layer.context | |||
| let queue = renderEntity.vertexBufferToCreate | |||
| while (queue.length) { | |||
| let index = queue.peek() | |||
| _vertexBufferJob.set(context, renderEntity, index) | |||
| if ( | |||
| !frameState.jobScheduler.execute(_vertexBufferJob, Cesium.JobType.BUFFER) | |||
| ) { | |||
| break | |||
| } | |||
| queue.dequeue() | |||
| } | |||
| } | |||
| function createIndexBuffers(renderEntity, frameState) { | |||
| let context = renderEntity.layer.context | |||
| let queue = renderEntity.indexBufferToCreate | |||
| while (queue.length) { | |||
| let index = queue.peek() | |||
| _indexBufferJob.set(context, renderEntity, index) | |||
| if ( | |||
| !frameState.jobScheduler.execute(_indexBufferJob, Cesium.JobType.BUFFER) | |||
| ) { | |||
| break | |||
| } | |||
| queue.dequeue() | |||
| } | |||
| } | |||
| function createShaderProgram(renderEntity, frameState) { | |||
| let context = renderEntity.layer.context | |||
| let queue = renderEntity.shaderProgramToCreate | |||
| while (queue.length) { | |||
| let index = queue.peek() | |||
| _shaderProgramJob.set(context, renderEntity) | |||
| if ( | |||
| !frameState.jobScheduler.execute( | |||
| _shaderProgramJob, | |||
| Cesium.JobType.PROGRAM | |||
| ) | |||
| ) { | |||
| break | |||
| } | |||
| queue.dequeue() | |||
| } | |||
| } | |||
| function createBatchTable(renderEntity, frameState) { | |||
| if (Cesium.defined(renderEntity.batchTable) || !renderEntity.pickInfo) { | |||
| return | |||
| } | |||
| const context = renderEntity.layer.context | |||
| let attributes = [] | |||
| attributes.push( | |||
| { | |||
| functionName: 'batchTable_operation', | |||
| componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE, | |||
| componentsPerAttribute: 4 | |||
| }, | |||
| { | |||
| functionName: 'batchTable_pickColor', | |||
| componentDatatype: Cesium.ComponentDatatype.UNSIGNED_BYTE, | |||
| componentsPerAttribute: 4, | |||
| normalize: true | |||
| } | |||
| ) | |||
| let pickInfo = renderEntity.pickInfo | |||
| let pickIds = Object.keys(pickInfo) | |||
| let numberOfInstances = | |||
| renderEntity.instanceCount > 0 ? renderEntity.instanceCount : pickIds.length | |||
| renderEntity.batchTable = new Cesium.BatchTable( | |||
| context, | |||
| attributes, | |||
| numberOfInstances | |||
| ) | |||
| } | |||
| RenderEntity.prototype.createBuffers = function(frameState) { | |||
| createVertexBuffers(this, frameState) | |||
| createIndexBuffers(this, frameState) | |||
| } | |||
| RenderEntity.prototype.createShaderProgram = function(frameState) { | |||
| createShaderProgram(this, frameState) | |||
| } | |||
| RenderEntity.prototype.createBatchTable = function(frameState) { | |||
| createBatchTable(this, frameState) | |||
| } | |||
| let scratchPntCenter = new Cesium.Cartesian3() | |||
| RenderEntity.prototype.createBoundingBoxForInstance = function() { | |||
| const vertexPackage = this.vertexPackage | |||
| if ( | |||
| !Cesium.defined(vertexPackage) || | |||
| vertexPackage.instanceIndex === -1 || | |||
| !Cesium.defined(vertexPackage.instanceBounds) | |||
| ) { | |||
| return | |||
| } | |||
| let instanceBounds = vertexPackage.instanceBounds | |||
| let pntLU = new Cesium.Cartesian3( | |||
| instanceBounds[0], | |||
| instanceBounds[1], | |||
| instanceBounds[2] | |||
| ) | |||
| let pntRD = new Cesium.Cartesian3( | |||
| instanceBounds[3], | |||
| instanceBounds[4], | |||
| instanceBounds[5] | |||
| ) | |||
| let pntCenter = Cesium.Cartesian3.lerp(pntLU, pntRD, 0.5, scratchPntCenter) | |||
| let dRadius = Cesium.Cartesian3.distance(pntCenter, pntLU) | |||
| let vecCenter = new Cesium.Cartesian3() | |||
| Cesium.Matrix4.multiplyByPoint(this.modelMatrix, pntCenter, vecCenter) | |||
| this.boundingVolume.center = vecCenter | |||
| this.boundingVolume.radius = dRadius | |||
| vertexPackage.instanceBounds = undefined | |||
| } | |||
| RenderEntity.prototype.initLayerSetting = function(layer) { | |||
| if (Object.keys(layer._objsOperationList).length > 0) { | |||
| this.updateObjsOperation(layer._objsOperationList) | |||
| } | |||
| } | |||
| let cartesian4Scratch = new Cesium.Cartesian4() | |||
| RenderEntity.prototype.createPickIds = function() { | |||
| const layer = this.layer | |||
| const context = layer.context | |||
| const pickInfo = this.pickInfo | |||
| if (!Cesium.defined(pickInfo)) { | |||
| return | |||
| } | |||
| for (let id in pickInfo) { | |||
| if (!pickInfo.hasOwnProperty(id)) { | |||
| continue | |||
| } | |||
| this.selectionInfoMap.set(id, pickInfo[id]) | |||
| } | |||
| let batchTable = this.batchTable | |||
| let selectionInfoMap = this.selectionInfoMap | |||
| let hash = selectionInfoMap._hash | |||
| for (let id in hash) { | |||
| if (hash.hasOwnProperty(id)) { | |||
| let selInfo = selectionInfoMap.get(id) | |||
| let pickId | |||
| if (!Cesium.defined(pickId)) { | |||
| pickId = context.createPickId({ | |||
| primitive: layer, | |||
| id: id | |||
| }) | |||
| } | |||
| let pickColor = pickId.color | |||
| cartesian4Scratch.x = Cesium.Color.floatToByte(pickColor.red) | |||
| cartesian4Scratch.y = Cesium.Color.floatToByte(pickColor.green) | |||
| cartesian4Scratch.z = Cesium.Color.floatToByte(pickColor.blue) | |||
| cartesian4Scratch.w = Cesium.Color.floatToByte(pickColor.alpha) | |||
| let instanceIds = selInfo.instanceIds | |||
| if (this.instanceCount > 0) { | |||
| instanceIds.map(function(instanceId) { | |||
| batchTable.setBatchedAttribute(instanceId, 1, cartesian4Scratch) | |||
| }) | |||
| } else { | |||
| let batchId = selInfo[0].batchId | |||
| batchTable.setBatchedAttribute(batchId, 1, cartesian4Scratch) | |||
| } | |||
| } | |||
| } | |||
| this.pickInfo = undefined | |||
| } | |||
| RenderEntity.prototype.updateBatchTableAttributes = function() { | |||
| let ro = this | |||
| let idsOperationMap = this.idsOperationMap | |||
| for (let i = 0, j = idsOperationMap.length; i < j; i++) { | |||
| let obj = idsOperationMap.values[i] | |||
| if (!obj.dirty) { | |||
| continue | |||
| } | |||
| obj.dirty = false | |||
| if (this.instanceCount > 0) { | |||
| if (Array.isArray(obj.instanceIds)) { | |||
| obj.instanceIds.map(function(instanceId) { | |||
| ro.batchTable.setBatchedAttribute(instanceId, 0, obj.operationValue) | |||
| }) | |||
| } | |||
| } else { | |||
| if (Cesium.defined(obj.batchId)) { | |||
| this.batchTable.setBatchedAttribute(obj.batchId, 0, obj.operationValue) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| RenderEntity.prototype.updateObjsOperation = function(ids) { | |||
| if (!this.ready || this.selectionInfoMap.length < 1) { | |||
| return | |||
| } | |||
| let selectValues = this.selectionInfoMap._hash | |||
| for (let id in selectValues) { | |||
| if (!selectValues.hasOwnProperty(id)) { | |||
| continue | |||
| } | |||
| let operationType = ids[id] | |||
| if (!Cesium.defined(operationType)) { | |||
| continue | |||
| } | |||
| let selectInfo = selectValues[id][0] | |||
| let batchId = selectInfo.batchId | |||
| let instanceIds = selectInfo.instanceIds | |||
| let obj = this.idsOperationMap.get(id) | |||
| if (!Cesium.defined(obj)) { | |||
| obj = { | |||
| batchId: batchId, | |||
| instanceIds: instanceIds, | |||
| operationValue: new Cesium.Cartesian4(), | |||
| dirty: true | |||
| } | |||
| } | |||
| obj.dirty = true | |||
| obj.operationValue.x = (obj.operationValue.x & 0x01) | operationType | |||
| this.idsOperationMap.set(id, obj) | |||
| this.batchTableDirty = true | |||
| } | |||
| } | |||
| RenderEntity.prototype.createCommand = | |||
| Cesium.DeveloperError.throwInstantiationError | |||
| RenderEntity.prototype.update = Cesium.DeveloperError.throwInstantiationError | |||
| RenderEntity.prototype.isDestroyed = | |||
| Cesium.DeveloperError.throwInstantiationError | |||
| RenderEntity.prototype.destroy = Cesium.DeveloperError.throwInstantiationError | |||
| export default RenderEntity | |||
| @@ -0,0 +1,210 @@ | |||
| import S3MTilesVS from '../Shaders/S3MTilesVS.js' | |||
| import S3MTilesFS from '../Shaders/S3MTilesFS.js' | |||
| import RenderEntity from './RenderEntity.js' | |||
| const { Cesium } = DC.Namespace | |||
| function S3MCacheFileRenderEntity(options) { | |||
| RenderEntity.call(this, options) | |||
| this.vs = S3MTilesVS | |||
| this.fs = S3MTilesFS | |||
| this.useLineColor = false | |||
| } | |||
| S3MCacheFileRenderEntity.prototype = Object.create(RenderEntity.prototype) | |||
| S3MCacheFileRenderEntity.prototype.constructor = RenderEntity | |||
| function getOpaqueRenderState() { | |||
| return Cesium.RenderState.fromCache({ | |||
| cull: { | |||
| enabled: false | |||
| }, | |||
| depthTest: { | |||
| enabled: true, | |||
| func: Cesium.DepthFunction.LESS_OR_EQUAL | |||
| }, | |||
| blending: Cesium.BlendingState.ALPHA_BLEND | |||
| }) | |||
| } | |||
| function getTransparentRenderState() { | |||
| return Cesium.RenderState.fromCache({ | |||
| cull: { | |||
| enabled: true | |||
| }, | |||
| depthTest: { | |||
| enabled: true, | |||
| func: Cesium.DepthFunction.LESS_OR_EQUAL | |||
| }, | |||
| blending: Cesium.BlendingState.ALPHA_BLEND | |||
| }) | |||
| } | |||
| function getUniformMap(material, layer, ro) { | |||
| return { | |||
| uGeoMatrix: function() { | |||
| return ro.geoMatrix | |||
| }, | |||
| uTexMatrix: function() { | |||
| return material.texMatrix | |||
| }, | |||
| uFillForeColor: function() { | |||
| if (ro.useLineColor) { | |||
| return layer.style3D.lineColor | |||
| } | |||
| return layer.style3D.fillForeColor | |||
| }, | |||
| uInverseGeoMatrix: function() { | |||
| return ro.invGeoMatrix | |||
| }, | |||
| uTexture: function() { | |||
| return material.textures[0] | |||
| }, | |||
| uTexture2: function() { | |||
| return material.textures[1] | |||
| }, | |||
| uTexture0Width: function() { | |||
| return material.textures[0].width | |||
| }, | |||
| uTexture1Width: function() { | |||
| return material.textures[1].width | |||
| }, | |||
| uDiffuseColor: function() { | |||
| return material.diffuseColor | |||
| }, | |||
| uSelectedColor: function() { | |||
| return layer._selectedColor | |||
| } | |||
| } | |||
| } | |||
| S3MCacheFileRenderEntity.prototype.createCommand = function() { | |||
| if ( | |||
| Cesium.defined(this.colorCommand) || | |||
| this.vertexBufferToCreate.length !== 0 || | |||
| this.indexBufferToCreate.length !== 0 || | |||
| this.shaderProgramToCreate.length !== 0 | |||
| ) { | |||
| return | |||
| } | |||
| let layer = this.layer | |||
| let context = layer.context | |||
| let vertexPackage = this.vertexPackage | |||
| let arrIndexPackage = this.arrIndexPackage | |||
| let attributes = vertexPackage.vertexAttributes | |||
| if (arrIndexPackage.length < 1) { | |||
| return | |||
| } | |||
| let indexPackage = arrIndexPackage[0] | |||
| let material = this.material | |||
| this.vertexArray = new Cesium.VertexArray({ | |||
| context: context, | |||
| attributes: attributes, | |||
| indexBuffer: indexPackage.indexBuffer | |||
| }) | |||
| let primitiveType = Cesium.PrimitiveType.TRIANGLES | |||
| switch (indexPackage.primitiveType) { | |||
| case 1: | |||
| primitiveType = Cesium.PrimitiveType.POINTS | |||
| break | |||
| case 2: | |||
| primitiveType = Cesium.PrimitiveType.LINES | |||
| break | |||
| case 4: | |||
| primitiveType = Cesium.PrimitiveType.TRIANGLES | |||
| break | |||
| default: | |||
| break | |||
| } | |||
| this.useLineColor = primitiveType === Cesium.PrimitiveType.LINES | |||
| this.colorCommand = new Cesium.DrawCommand({ | |||
| primitiveType: primitiveType, | |||
| modelMatrix: this.modelMatrix, | |||
| boundingVolume: Cesium.BoundingSphere.clone(this.boundingVolume), | |||
| pickId: this.pickColorIdentifier, | |||
| vertexArray: this.vertexArray, | |||
| shaderProgram: this.shaderProgram, | |||
| pass: material.bTransparentSorting | |||
| ? Cesium.Pass.TRANSLUCENT | |||
| : Cesium.Pass.OPAQUE, | |||
| renderState: material.bTransparentSorting | |||
| ? getTransparentRenderState() | |||
| : getOpaqueRenderState(), | |||
| instanceCount: vertexPackage.instanceCount | |||
| }) | |||
| let uniformMap = getUniformMap(material, layer, this) | |||
| if (this.batchTable) { | |||
| uniformMap = this.batchTable.getUniformMapCallback()(uniformMap) | |||
| } | |||
| this.colorCommand.uniformMap = uniformMap | |||
| this.vertexPackage = undefined | |||
| this.arrIndexPackage = undefined | |||
| this.vs = undefined | |||
| this.fs = undefined | |||
| this.ready = true | |||
| } | |||
| S3MCacheFileRenderEntity.prototype.update = function(frameState, layer) { | |||
| if (!this.ready) { | |||
| this.createBatchTable(frameState) | |||
| this.createPickIds() | |||
| this.createBuffers(frameState) | |||
| this.createShaderProgram(frameState) | |||
| this.createCommand(frameState) | |||
| this.initLayerSetting(layer) | |||
| return | |||
| } | |||
| if (this.batchTableDirty) { | |||
| this.updateBatchTableAttributes() | |||
| this.batchTableDirty = false | |||
| } | |||
| if (this.batchTable) { | |||
| this.batchTable.update(frameState) | |||
| } | |||
| frameState.commandList.push(this.colorCommand) | |||
| } | |||
| S3MCacheFileRenderEntity.prototype.isDestroyed = function() { | |||
| return false | |||
| } | |||
| S3MCacheFileRenderEntity.prototype.destroy = function() { | |||
| this.shaderProgram = | |||
| this.shaderProgram && | |||
| !this.shaderProgram.isDestroyed() && | |||
| this.shaderProgram.destroy() | |||
| this.vertexArray = | |||
| this.vertexArray && | |||
| !this.vertexArray.isDestroyed() && | |||
| this.vertexArray.destroy() | |||
| this.material = | |||
| this.material && !this.material.isDestroyed() && this.material.destroy() | |||
| this.batchTable = | |||
| this.batchTable && | |||
| !this.batchTable.isDestroyed() && | |||
| this.batchTable.destroy() | |||
| this.colorCommand = undefined | |||
| this.vertexPackage = null | |||
| this.arrIndexPackage = null | |||
| this.modelMatrix = undefined | |||
| this.pickInfo = undefined | |||
| this.selectionInfoMap = undefined | |||
| this.vs = undefined | |||
| this.fs = undefined | |||
| return Cesium.destroyObject(this) | |||
| } | |||
| export default S3MCacheFileRenderEntity | |||
| @@ -0,0 +1,12 @@ | |||
| import S3MCacheFileRenderEntity from './S3MCacheFileRenderEntity.js' | |||
| import S3MObliqueRenderEntity from './S3MObliqueRenderEntity.js' | |||
| let S3MContentFactory = { | |||
| OSGBFile: function(options) { | |||
| return new S3MObliqueRenderEntity(options) | |||
| }, | |||
| OSGBCacheFile: function(options) { | |||
| return new S3MCacheFileRenderEntity(options) | |||
| } | |||
| } | |||
| export default S3MContentFactory | |||
| @@ -0,0 +1,134 @@ | |||
| import S3MTilesNoLightVS from '../Shaders/S3MTilesNoLightVS.js' | |||
| import S3MTilesNoLightFS from '../Shaders/S3MTilesNoLightFS.js' | |||
| import RenderEntity from './RenderEntity.js' | |||
| const { Cesium } = DC.Namespace | |||
| function S3MObliqueRenderEntity(options) { | |||
| RenderEntity.call(this, options) | |||
| this.vs = S3MTilesNoLightVS | |||
| this.fs = S3MTilesNoLightFS | |||
| } | |||
| S3MObliqueRenderEntity.prototype = Object.create(RenderEntity.prototype) | |||
| S3MObliqueRenderEntity.prototype.constructor = RenderEntity | |||
| function getOpaqueRenderState() { | |||
| return Cesium.RenderState.fromCache({ | |||
| cull: { | |||
| enabled: true | |||
| }, | |||
| depthTest: { | |||
| enabled: true, | |||
| func: Cesium.DepthFunction.LESS_OR_EQUAL | |||
| }, | |||
| blending: Cesium.BlendingState.ALPHA_BLEND | |||
| }) | |||
| } | |||
| function getUniformMap(material, layer, ro) { | |||
| return { | |||
| uGeoMatrix: function() { | |||
| return ro.geoMatrix | |||
| }, | |||
| uInverseGeoMatrix: function() { | |||
| return ro.invGeoMatrix | |||
| }, | |||
| uTexture: function() { | |||
| return material.textures[0] | |||
| }, | |||
| uTexture0Width: function() { | |||
| return material.textures[0].width | |||
| } | |||
| } | |||
| } | |||
| S3MObliqueRenderEntity.prototype.createCommand = function() { | |||
| if ( | |||
| Cesium.defined(this.colorCommand) || | |||
| this.vertexBufferToCreate.length !== 0 || | |||
| this.indexBufferToCreate.length !== 0 || | |||
| this.shaderProgramToCreate.length !== 0 | |||
| ) { | |||
| return | |||
| } | |||
| let layer = this.layer | |||
| let context = layer.context | |||
| let vertexPackage = this.vertexPackage | |||
| let arrIndexPackage = this.arrIndexPackage | |||
| let attributes = vertexPackage.vertexAttributes | |||
| if (arrIndexPackage.length < 1) { | |||
| return | |||
| } | |||
| let indexPackage = arrIndexPackage[0] | |||
| let material = this.material | |||
| this.vertexArray = new Cesium.VertexArray({ | |||
| context: context, | |||
| attributes: attributes, | |||
| indexBuffer: indexPackage.indexBuffer | |||
| }) | |||
| this.colorCommand = new Cesium.DrawCommand({ | |||
| primitiveType: indexPackage.primitiveType, | |||
| modelMatrix: this.modelMatrix, | |||
| boundingVolume: Cesium.BoundingSphere.clone(this.boundingVolume), | |||
| vertexArray: this.vertexArray, | |||
| shaderProgram: this.shaderProgram, | |||
| pass: material.bTransparentSorting | |||
| ? Cesium.Pass.TRANSLUCENT | |||
| : Cesium.Pass.OPAQUE, | |||
| renderState: getOpaqueRenderState(), | |||
| instanceCount: vertexPackage.instanceCount | |||
| }) | |||
| this.colorCommand.uniformMap = getUniformMap(material, layer, this) | |||
| this.vertexPackage = undefined | |||
| this.arrIndexPackage = undefined | |||
| this.vs = undefined | |||
| this.fs = undefined | |||
| this.ready = true | |||
| } | |||
| S3MObliqueRenderEntity.prototype.update = function(frameState, layer) { | |||
| if (!this.ready) { | |||
| this.createBuffers(frameState) | |||
| this.createShaderProgram(frameState) | |||
| this.createCommand(frameState) | |||
| this.initLayerSetting(layer) | |||
| return | |||
| } | |||
| frameState.commandList.push(this.colorCommand) | |||
| } | |||
| S3MObliqueRenderEntity.prototype.isDestroyed = function() { | |||
| return false | |||
| } | |||
| S3MObliqueRenderEntity.prototype.destroy = function() { | |||
| this.shaderProgram = | |||
| this.shaderProgram && | |||
| !this.shaderProgram.isDestroyed() && | |||
| this.shaderProgram.destroy() | |||
| this.vertexArray = | |||
| this.vertexArray && | |||
| !this.vertexArray.isDestroyed() && | |||
| this.vertexArray.destroy() | |||
| this.material = | |||
| this.material && !this.material.isDestroyed() && this.material.destroy() | |||
| this.colorCommand = undefined | |||
| this.vertexPackage = null | |||
| this.arrIndexPackage = null | |||
| this.modelMatrix = undefined | |||
| this.pickInfo = undefined | |||
| this.selectionInfoMap = undefined | |||
| this.vs = undefined | |||
| this.fs = undefined | |||
| return Cesium.destroyObject(this) | |||
| } | |||
| export default S3MObliqueRenderEntity | |||
| @@ -0,0 +1,34 @@ | |||
| const { Cesium } = DC.Namespace | |||
| function MaterialPass() { | |||
| this.ambientColor = new Cesium.Color() | |||
| this.diffuseColor = new Cesium.Color() | |||
| this.specularColor = new Cesium.Color(0.0, 0.0, 0.0, 0.0) | |||
| this.shininess = 50.0 | |||
| this.bTransparentSorting = false | |||
| this.texMatrix = Cesium.Matrix4.clone( | |||
| Cesium.Matrix4.IDENTITY, | |||
| new Cesium.Matrix4() | |||
| ) | |||
| this.textures = [] | |||
| } | |||
| MaterialPass.prototype.isDestroyed = function() { | |||
| return false | |||
| } | |||
| MaterialPass.prototype.destroy = function() { | |||
| let length = this.textures.length | |||
| for (let i = 0; i < length; i++) { | |||
| let texture = this.textures[i] | |||
| texture.destroy() | |||
| } | |||
| this.textures.length = 0 | |||
| this.ambientColor = undefined | |||
| this.diffuseColor = undefined | |||
| this.specularColor = undefined | |||
| return Cesium.destroyObject(this) | |||
| } | |||
| export default MaterialPass | |||
| @@ -0,0 +1,301 @@ | |||
| import DDSTexture from './DDSTexture.js' | |||
| import MaterialPass from './MaterialPass.js' | |||
| import S3MContentFactory from './Factory/S3MContentFactory.js' | |||
| import VertexCompressOption from './Enum/VertexCompressOption.js' | |||
| const { Cesium } = DC.Namespace | |||
| function S3MContentParser() {} | |||
| function parseMaterial(context, content, tile) { | |||
| let materialTable = {} | |||
| let materials = content.materials.material | |||
| for (let i = 0, j = materials.length; i < j; i++) { | |||
| let material = materials[i].material | |||
| let materialCode = material.id | |||
| let materialPass = new MaterialPass() | |||
| materialTable[materialCode] = materialPass | |||
| let ambient = material.ambient | |||
| materialPass.ambientColor = new Cesium.Color( | |||
| ambient.r, | |||
| ambient.g, | |||
| ambient.b, | |||
| ambient.a | |||
| ) | |||
| let diffuse = material.diffuse | |||
| materialPass.diffuseColor = new Cesium.Color( | |||
| diffuse.r, | |||
| diffuse.g, | |||
| diffuse.b, | |||
| diffuse.a | |||
| ) | |||
| let specular = material.specular | |||
| materialPass.specularColor = new Cesium.Color( | |||
| specular.r, | |||
| specular.g, | |||
| specular.b, | |||
| specular.a | |||
| ) | |||
| materialPass.shininess = material.shininess | |||
| materialPass.bTransparentSorting = material.transparentsorting | |||
| let textureStates = material.textureunitstates | |||
| let len = textureStates.length | |||
| for (let k = 0; k < len; k++) { | |||
| let textureState = textureStates[k].textureunitstate | |||
| let textureCode = textureState.id | |||
| let wrapS = | |||
| textureState.addressmode.u === 0 | |||
| ? Cesium.TextureWrap.REPEAT | |||
| : Cesium.TextureWrap.CLAMP_TO_EDGE | |||
| let wrapT = | |||
| textureState.addressmode.v === 0 | |||
| ? Cesium.TextureWrap.REPEAT | |||
| : Cesium.TextureWrap.CLAMP_TO_EDGE | |||
| materialPass.texMatrix = Cesium.Matrix4.unpack(textureState.texmodmatrix) | |||
| let textureInfo = content.texturePackage[textureCode] | |||
| if ( | |||
| Cesium.defined(textureInfo) && | |||
| textureInfo.arrayBufferView.byteLength > 0 | |||
| ) { | |||
| textureInfo.wrapS = wrapS | |||
| textureInfo.wrapT = wrapT | |||
| let keyword = tile.fileName + textureCode | |||
| let texture = context.textureCache.getTexture(keyword) | |||
| if (!Cesium.defined(texture)) { | |||
| if ( | |||
| Cesium.PixelFormat.isCompressedFormat(textureInfo.internalFormat) | |||
| ) { | |||
| texture = new DDSTexture(context, textureCode, textureInfo) | |||
| } else { | |||
| let isPowerOfTwo = | |||
| Cesium.Math.isPowerOfTwo(textureInfo.width) && | |||
| Cesium.Math.isPowerOfTwo(textureInfo.height) | |||
| texture = new Cesium.Texture({ | |||
| context: context, | |||
| source: { | |||
| width: textureInfo.width, | |||
| height: textureInfo.height, | |||
| arrayBufferView: textureInfo.arrayBufferView | |||
| }, | |||
| sampler: new Cesium.Sampler({ | |||
| minificationFilter: isPowerOfTwo | |||
| ? context._gl.LINEAR_MIPMAP_LINEAR | |||
| : context._gl.LINEAR, | |||
| wrapS: wrapS, | |||
| wrapT: wrapT | |||
| }) | |||
| }) | |||
| if (isPowerOfTwo) { | |||
| texture.generateMipmap(Cesium.MipmapHint.NICEST) | |||
| } | |||
| } | |||
| context.textureCache.addTexture(keyword, texture) | |||
| } | |||
| materialPass.textures.push(texture) | |||
| } | |||
| } | |||
| } | |||
| return materialTable | |||
| } | |||
| function calcBoundingVolumeForNormal(vertexPackage, modelMatrix) { | |||
| let boundingSphere = new Cesium.BoundingSphere() | |||
| let v1 = new Cesium.Cartesian3() | |||
| let positionAttr = vertexPackage.vertexAttributes[0] | |||
| let dim = positionAttr.componentsPerAttribute | |||
| let isCompress = | |||
| Cesium.defined(vertexPackage.compressOptions) && | |||
| (vertexPackage.compressOptions & VertexCompressOption.SVC_Vertex) === | |||
| VertexCompressOption.SVC_Vertex | |||
| let normConstant = 1.0 | |||
| let minVertex | |||
| let vertexTypedArray | |||
| if (isCompress) { | |||
| normConstant = vertexPackage.vertCompressConstant | |||
| minVertex = new Cesium.Cartesian3( | |||
| vertexPackage.minVerticesValue.x, | |||
| vertexPackage.minVerticesValue.y, | |||
| vertexPackage.minVerticesValue.z | |||
| ) | |||
| vertexTypedArray = new Uint16Array( | |||
| positionAttr.typedArray.buffer, | |||
| positionAttr.typedArray.byteOffset, | |||
| positionAttr.typedArray.byteLength / 2 | |||
| ) | |||
| } else { | |||
| vertexTypedArray = new Float32Array( | |||
| positionAttr.typedArray.buffer, | |||
| positionAttr.typedArray.byteOffset, | |||
| positionAttr.typedArray.byteLength / 4 | |||
| ) | |||
| } | |||
| let vertexArray = [] | |||
| for (let t = 0; t < vertexPackage.verticesCount; t++) { | |||
| Cesium.Cartesian3.fromArray(vertexTypedArray, dim * t, v1) | |||
| if (isCompress) { | |||
| v1 = Cesium.Cartesian3.multiplyByScalar(v1, normConstant, v1) | |||
| v1 = Cesium.Cartesian3.add(v1, minVertex, v1) | |||
| } | |||
| vertexArray.push(Cesium.Cartesian3.clone(v1)) | |||
| } | |||
| Cesium.BoundingSphere.fromPoints(vertexArray, boundingSphere) | |||
| Cesium.BoundingSphere.transform(boundingSphere, modelMatrix, boundingSphere) | |||
| vertexArray.length = 0 | |||
| return boundingSphere | |||
| } | |||
| let scratchCenter = new Cesium.Cartesian3() | |||
| function calcBoundingVolumeForInstance(vertexPackage) { | |||
| let boundingSphere = new Cesium.BoundingSphere() | |||
| let boundingsValues = vertexPackage.instanceBounds | |||
| if (!Cesium.defined(boundingsValues)) { | |||
| return boundingSphere | |||
| } | |||
| let pntLU = new Cesium.Cartesian3( | |||
| boundingsValues[0], | |||
| boundingsValues[1], | |||
| boundingsValues[2] | |||
| ) | |||
| let pntRD = new Cesium.Carteisan3( | |||
| boundingsValues[3], | |||
| boundingsValues[4], | |||
| boundingsValues[5] | |||
| ) | |||
| let center = new Cesium.Cartesian3.lerp(pntLU, pntRD, 0.5, scratchCenter) | |||
| let radius = new Cesium.Cartesian3.distance(center, pntLU) | |||
| boundingSphere.center = center | |||
| boundingSphere.radius = radius | |||
| return boundingSphere | |||
| } | |||
| function calcBoundingVolume(vertexPackage, modelMatrix) { | |||
| if (vertexPackage.instanceIndex > -1) { | |||
| return calcBoundingVolumeForInstance(vertexPackage) | |||
| } | |||
| return calcBoundingVolumeForNormal(vertexPackage, modelMatrix) | |||
| } | |||
| function parseGeodes(layer, content, materialTable, pagelodNode, pagelod) { | |||
| let geoMap = {} | |||
| let geodeList = pagelodNode.geodes | |||
| for (let i = 0, j = geodeList.length; i < j; i++) { | |||
| let geodeNode = geodeList[i] | |||
| let geoMatrix = geodeNode.matrix | |||
| let modelMatrix = Cesium.Matrix4.multiply( | |||
| layer.modelMatrix, | |||
| geoMatrix, | |||
| new Cesium.Matrix4() | |||
| ) | |||
| let boundingSphere | |||
| if (Cesium.defined(pagelod.boundingVolume)) { | |||
| boundingSphere = new Cesium.BoundingSphere( | |||
| pagelod.boundingVolume.sphere.center, | |||
| pagelod.boundingVolume.sphere.radius | |||
| ) | |||
| Cesium.BoundingSphere.transform( | |||
| boundingSphere, | |||
| layer.modelMatrix, | |||
| boundingSphere | |||
| ) | |||
| } | |||
| let skeletonNames = geodeNode.skeletonNames | |||
| for (let m = 0, n = skeletonNames.length; m < n; m++) { | |||
| let geoName = skeletonNames[m] | |||
| let geoPackage = content.geoPackage[geoName] | |||
| let vertexPackage = geoPackage.vertexPackage | |||
| let arrIndexPackage = geoPackage.arrIndexPackage | |||
| let pickInfo = geoPackage.pickInfo | |||
| let material | |||
| if (arrIndexPackage.length > 0) { | |||
| material = materialTable[arrIndexPackage[0].materialCode] | |||
| } | |||
| let geodeBoundingVolume = Cesium.defined(boundingSphere) | |||
| ? boundingSphere | |||
| : calcBoundingVolume(vertexPackage, modelMatrix) | |||
| geoMap[geoName] = S3MContentFactory[layer.fileType]({ | |||
| layer: layer, | |||
| vertexPackage: vertexPackage, | |||
| arrIndexPackage: arrIndexPackage, | |||
| pickInfo: pickInfo, | |||
| modelMatrix: modelMatrix, | |||
| geoMatrix: geoMatrix, | |||
| boundingVolume: geodeBoundingVolume, | |||
| material: material, | |||
| edgeGeometry: geoPackage.edgeGeometry, | |||
| geoName: geoName | |||
| }) | |||
| } | |||
| } | |||
| if (Object.keys(geoMap).length < 1) { | |||
| return | |||
| } | |||
| if (!Cesium.defined(pagelod.boundingVolume)) { | |||
| let arr = [] | |||
| for (let key in geoMap) { | |||
| if (geoMap.hasOwnProperty(key)) { | |||
| arr.push(geoMap[key].boundingVolume) | |||
| } | |||
| } | |||
| pagelod.boundingVolume = { | |||
| sphere: Cesium.BoundingSphere.fromBoundingSpheres(arr) | |||
| } | |||
| } | |||
| pagelod.geoMap = geoMap | |||
| } | |||
| function parsePagelods(layer, content, materialTable) { | |||
| let groupNode = content.groupNode | |||
| let pagelods = [] | |||
| for (let i = 0, j = groupNode.pageLods.length; i < j; i++) { | |||
| let pagelod = {} | |||
| let pagelodNode = groupNode.pageLods[i] | |||
| pagelod.rangeMode = pagelodNode.rangeMode | |||
| pagelod.rangeDataList = pagelodNode.childTile | |||
| pagelod.rangeList = pagelodNode.rangeList | |||
| let center = pagelodNode.boundingSphere.center | |||
| let radius = pagelodNode.boundingSphere.radius | |||
| if (pagelod.rangeDataList !== '') { | |||
| pagelod.boundingVolume = { | |||
| sphere: { | |||
| center: new Cesium.Cartesian3(center.x, center.y, center.z), | |||
| radius: radius | |||
| } | |||
| } | |||
| } else { | |||
| pagelod.isLeafTile = true | |||
| } | |||
| parseGeodes(layer, content, materialTable, pagelodNode, pagelod) | |||
| if (Cesium.defined(pagelod.geoMap)) { | |||
| pagelods.push(pagelod) | |||
| } | |||
| } | |||
| return pagelods | |||
| } | |||
| S3MContentParser.parse = function(layer, content, tile) { | |||
| if (!Cesium.defined(content)) { | |||
| return | |||
| } | |||
| let materialTable = parseMaterial(layer.context, content, tile) | |||
| let pagelods = parsePagelods(layer, content, materialTable) | |||
| return pagelods | |||
| } | |||
| export default S3MContentParser | |||
| @@ -0,0 +1,50 @@ | |||
| const { Cesium } = DC.Namespace | |||
| function S3MCreateIndexBufferJob(){ | |||
| this.model = undefined; | |||
| this.context = undefined; | |||
| this.index = 0; | |||
| } | |||
| S3MCreateIndexBufferJob.prototype.set = function(context, model, index) { | |||
| this.model = model; | |||
| this.context = context; | |||
| this.index = index; | |||
| }; | |||
| S3MCreateIndexBufferJob.prototype.execute = function(){ | |||
| let context = this.context; | |||
| let indexPackage = this.model.arrIndexPackage[this.index]; | |||
| let verticesCount = this.model.vertexPackage.verticesCount; | |||
| if(!Cesium.defined(indexPackage)){ | |||
| throw new Cesium.DeveloperError('index package is null'); | |||
| } | |||
| if(Cesium.defined(indexPackage.indexBuffer)){ | |||
| return ; | |||
| } | |||
| if(!Cesium.defined(indexPackage.indicesTypedArray)){ | |||
| throw new Cesium.DeveloperError('index buffer is null'); | |||
| } | |||
| let indexDataType = Cesium.IndexDatatype.UNSIGNED_SHORT; | |||
| if((indexPackage.indexType === 1 || verticesCount >= Cesium.Math.SIXTY_FOUR_KILOBYTES) && context.elementIndexUint) { | |||
| indexDataType = Cesium.IndexDatatype.UNSIGNED_INT; | |||
| } | |||
| if(!Cesium.defined(indexPackage.indexBuffer)){ | |||
| indexPackage.indexBuffer = Cesium.Buffer.createIndexBuffer({ | |||
| context : context, | |||
| typedArray : indexPackage.indicesTypedArray, | |||
| usage : Cesium.BufferUsage.STATIC_DRAW, | |||
| indexDatatype : indexDataType | |||
| }); | |||
| } | |||
| indexPackage.indicesTypedArray = null; | |||
| delete indexPackage.indicesTypedArray; | |||
| }; | |||
| export default S3MCreateIndexBufferJob; | |||
| @@ -0,0 +1,115 @@ | |||
| const { Cesium } = DC.Namespace | |||
| import ProgramDefines from './Enum/ProgramDefines.js'; | |||
| import VertexCompressOption from './Enum/VertexCompressOption.js'; | |||
| import InstanceMode from './Enum/InstanceMode.js'; | |||
| function S3MCreateShaderProgramJob(){ | |||
| this.model = undefined; | |||
| this.context = undefined; | |||
| } | |||
| S3MCreateShaderProgramJob.prototype.set = function(context, model) { | |||
| this.model = model; | |||
| this.context = context; | |||
| }; | |||
| function getExtension(gl, names) { | |||
| let length = names.length; | |||
| for (let i = 0; i < length; ++i) { | |||
| let extension = gl.getExtension(names[i]); | |||
| if (extension) { | |||
| return extension; | |||
| } | |||
| } | |||
| return undefined; | |||
| } | |||
| S3MCreateShaderProgramJob.prototype.execute = function(){ | |||
| const context = this.context; | |||
| const model = this.model; | |||
| const layer = model.layer; | |||
| const vs = model.vs; | |||
| const fs = model.fs; | |||
| const attributeLocations = model.attributeLocations; | |||
| const material = model.material; | |||
| const vertexPackage = model.vertexPackage; | |||
| let vsNew = model.batchTable ? model.batchTable.getVertexShaderCallback()(vs) : vs; | |||
| if(context.texturelod === undefined){ | |||
| context.texturelod = Cesium.defaultValue(getExtension(context._gl, ['EXT_shader_texture_lod']), false); | |||
| } | |||
| let vp = new Cesium.ShaderSource({ | |||
| sources : [vsNew] | |||
| }); | |||
| let fp = new Cesium.ShaderSource({ | |||
| sources : [fs] | |||
| }); | |||
| if(Cesium.defined(attributeLocations['aNormal'])) { | |||
| vp.defines.push(ProgramDefines.VertexNormal); | |||
| fp.defines.push(ProgramDefines.VertexNormal); | |||
| } | |||
| if(Cesium.defined(attributeLocations['aColor'])) { | |||
| vp.defines.push(ProgramDefines.VertexColor); | |||
| } | |||
| if(material && material.textures.length > 0) { | |||
| vp.defines.push(ProgramDefines.COMPUTE_TEXCOORD); | |||
| fp.defines.push(ProgramDefines.COMPUTE_TEXCOORD); | |||
| } | |||
| if(material && material.textures.length === 2) { | |||
| vp.defines.push(ProgramDefines.TexCoord2); | |||
| fp.defines.push(ProgramDefines.TexCoord2); | |||
| } | |||
| if(Cesium.defined(attributeLocations['aTexCoord0'])) { | |||
| vp.defines.push('TexCoord'); | |||
| fp.defines.push('TexCoord'); | |||
| } | |||
| if(vertexPackage.instanceIndex > -1){ | |||
| vp.defines.push(ProgramDefines.Instance); | |||
| } | |||
| if(vertexPackage.instanceMode === InstanceMode.BIM){ | |||
| vp.defines.push(ProgramDefines.InstanceBim); | |||
| } | |||
| if(Cesium.defined(vertexPackage.compressOptions)){ | |||
| let compressOptions = vertexPackage.compressOptions; | |||
| if((compressOptions & VertexCompressOption.SVC_Vertex) === VertexCompressOption.SVC_Vertex){ | |||
| vp.defines.push(ProgramDefines.COMPRESS_VERTEX); | |||
| } | |||
| if((compressOptions & VertexCompressOption.SVC_Normal) === VertexCompressOption.SVC_Normal){ | |||
| vp.defines.push(ProgramDefines.COMPRESS_NORMAL); | |||
| } | |||
| if((compressOptions & VertexCompressOption.SVC_VertexColor) === VertexCompressOption.SVC_VertexColor){ | |||
| vp.defines.push(ProgramDefines.COMPRESS_COLOR); | |||
| } | |||
| if((compressOptions & VertexCompressOption.SVC_TexutreCoord) === VertexCompressOption.SVC_TexutreCoord){ | |||
| vp.defines.push(ProgramDefines.COMPRESS_TEXCOORD); | |||
| } | |||
| } | |||
| if(Cesium.defined(model.arrIndexPackage) && model.arrIndexPackage.length > 0 && model.arrIndexPackage[0].primitiveType === 2){ | |||
| fp.defines.push(ProgramDefines.UseLineColor); | |||
| } | |||
| model.shaderProgram = Cesium.ShaderProgram.fromCache({ | |||
| context : context, | |||
| vertexShaderSource : vp, | |||
| fragmentShaderSource : fp, | |||
| attributeLocations : attributeLocations | |||
| }); | |||
| }; | |||
| export default S3MCreateShaderProgramJob; | |||
| @@ -0,0 +1,55 @@ | |||
| const { Cesium } = DC.Namespace | |||
| function S3MCreateVertexJob(){ | |||
| this.context = undefined; | |||
| this.model = undefined; | |||
| this.index = undefined; | |||
| } | |||
| S3MCreateVertexJob.prototype.set = function(context, model, index) { | |||
| this.context = context; | |||
| this.model = model; | |||
| this.index = index; | |||
| }; | |||
| S3MCreateVertexJob.prototype.execute = function(){ | |||
| let context = this.context; | |||
| let index = this.index; | |||
| let vertexPackage = this.model.vertexPackage; | |||
| let attr = vertexPackage.vertexAttributes[index]; | |||
| if(!Cesium.defined(attr)){ | |||
| throw new Cesium.DeveloperError('attribute is null'); | |||
| } | |||
| if(vertexPackage.instanceIndex !== -1 && !Cesium.defined(this.model.instanceBuffer)){ | |||
| if(!Cesium.defined(vertexPackage.instanceBuffer)){ | |||
| throw new Cesium.DeveloperError('instance buffer is null'); | |||
| } | |||
| this.model.instanceBuffer = Cesium.Buffer.createVertexBuffer({ | |||
| context : context, | |||
| typedArray : vertexPackage.instanceBuffer, | |||
| usage : Cesium.BufferUsage.STATIC_DRAW | |||
| }); | |||
| } | |||
| if(attr.instanceDivisor === 1 && !Cesium.defined(attr.typedArray)){ | |||
| attr.vertexBuffer = this.model.instanceBuffer; | |||
| return ; | |||
| } | |||
| if(!Cesium.defined(attr.vertexBuffer)){ | |||
| attr.vertexBuffer = Cesium.Buffer.createVertexBuffer({ | |||
| context : context, | |||
| typedArray : attr.typedArray, | |||
| usage : Cesium.BufferUsage.STATIC_DRAW | |||
| }); | |||
| attr.typedArray = null; | |||
| delete attr.typedArray; | |||
| } | |||
| }; | |||
| export default S3MCreateVertexJob; | |||
| @@ -0,0 +1,56 @@ | |||
| const { Cesium } = DC.Namespace | |||
| function S3MLayerCache() { | |||
| this._list = new Cesium.DoublyLinkedList(); | |||
| this._sentinel = this._list.add(); | |||
| this._trimTiles = false; | |||
| } | |||
| S3MLayerCache.prototype.reset = function() { | |||
| this._list.splice(this._list.tail, this._sentinel); | |||
| }; | |||
| S3MLayerCache.prototype.touch = function(tile) { | |||
| let node = tile.cacheNode; | |||
| if (Cesium.defined(node)) { | |||
| this._list.splice(this._sentinel, node); | |||
| } | |||
| }; | |||
| S3MLayerCache.prototype.add = function(tile) { | |||
| if (!Cesium.defined(tile.cacheNode)) { | |||
| tile.cacheNode = this._list.add(tile); | |||
| } | |||
| }; | |||
| S3MLayerCache.prototype.unloadTile = function(layer, tile, unloadCallback) { | |||
| let node = tile.cacheNode; | |||
| if (!Cesium.defined(node)) { | |||
| return; | |||
| } | |||
| this._list.remove(node); | |||
| tile.cacheNode = undefined; | |||
| unloadCallback(layer, tile); | |||
| }; | |||
| S3MLayerCache.prototype.unloadTiles = function(layer, unloadCallback) { | |||
| let trimTiles = this._trimTiles; | |||
| this._trimTiles = false; | |||
| let list = this._list; | |||
| let maximumMemoryUsageInBytes = layer.maximumMemoryUsage * 1024 * 1024; | |||
| let sentinel = this._sentinel; | |||
| let node = list.head; | |||
| while (node && (node !== sentinel) && ((layer.totalMemoryUsageInBytes > maximumMemoryUsageInBytes) || trimTiles)) { | |||
| let tile = node.item; | |||
| node = node.next; | |||
| this.unloadTile(layer, tile, unloadCallback); | |||
| } | |||
| }; | |||
| S3MLayerCache.prototype.trim = function() { | |||
| this._trimTiles = true; | |||
| }; | |||
| export default S3MLayerCache; | |||
| @@ -0,0 +1,212 @@ | |||
| const { Cesium } = DC.Namespace | |||
| import ContentState from './Enum/ContentState.js'; | |||
| import RangeMode from './Enum/RangeMode.js'; | |||
| function S3MLayerScheduler (){ | |||
| this._stack = []; | |||
| } | |||
| function sortComparator(a, b) { | |||
| if (b.distanceToCamera === 0 && a.distanceToCamera === 0) { | |||
| return b.centerZDepth - a.centerZDepth; | |||
| } | |||
| return b.distanceToCamera - a.distanceToCamera; | |||
| } | |||
| function updateChildren(layer, tile, stack, frameState) { | |||
| let i; | |||
| let children = tile.children; | |||
| let length = children.length; | |||
| for (i = 0; i < length; ++i) { | |||
| updateTile(frameState, layer, children[i]); | |||
| } | |||
| children.sort(sortComparator); | |||
| let refines = true; | |||
| let anyChildrenVisible = false; | |||
| let minIndex = -1; | |||
| let minimumPriority = Number.MAX_VALUE; | |||
| let checkChildRefins = true; | |||
| for (i = 0; i < length; ++i) { | |||
| let child = children[i]; | |||
| if (child.foveatedFactor < minimumPriority) { | |||
| minIndex = i; | |||
| minimumPriority = child.foveatedFactor; | |||
| } | |||
| if (child.visible) { | |||
| stack.push(child); | |||
| anyChildrenVisible = true; | |||
| } else { | |||
| loadTile(layer, child, frameState); | |||
| touchTile(layer, child, frameState); | |||
| processTile(layer, child, frameState); | |||
| } | |||
| let childRefines = child.renderable; | |||
| if(checkChildRefins){ | |||
| refines = refines && childRefines; | |||
| } | |||
| } | |||
| if (!anyChildrenVisible) { | |||
| refines = false; | |||
| } | |||
| if (minIndex !== -1) { | |||
| let minPriorityChild = children[minIndex]; | |||
| minPriorityChild.wasMinPriorityChild = true; | |||
| let priorityHolder = (tile.wasMinPriorityChild || tile.isRootTile) && | |||
| minimumPriority <= tile.priorityHolder.foveatedFactor ? tile.priorityHolder : tile; | |||
| priorityHolder.foveatedFactor = Math.min(minPriorityChild.foveatedFactor, priorityHolder.foveatedFactor); | |||
| priorityHolder.distanceToCamera = Math.min(minPriorityChild.distanceToCamera, priorityHolder.distanceToCamera); | |||
| for (i = 0; i < length; ++i) { | |||
| let child = children[i]; | |||
| child.priorityHolder = priorityHolder; | |||
| } | |||
| } | |||
| return refines; | |||
| } | |||
| function selectTile(layer, tile, frameState) { | |||
| if(tile.selectedFrame === frameState.frameNumber || !tile.renderable){ | |||
| return ; | |||
| } | |||
| layer._selectedTiles.push(tile); | |||
| tile.selectedFrame = frameState.frameNumber; | |||
| } | |||
| function loadTile(layer, tile, frameState) { | |||
| if(tile.requestedFrame === frameState.frameNumber || tile.contentState !== ContentState.UNLOADED) { | |||
| return ; | |||
| } | |||
| layer._requestTiles.push(tile); | |||
| tile.requestedFrame = frameState.frameNumber; | |||
| } | |||
| function processTile(layer, tile, frameState) { | |||
| if(tile.processFrame === frameState.frameNumber || tile.contentState !== ContentState.READY || tile.renderable) { | |||
| return ; | |||
| } | |||
| tile.processFrame = frameState.frameNumber; | |||
| layer._processTiles.push(tile); | |||
| } | |||
| function touchTile(layer, tile, frameState) { | |||
| if (tile.touchedFrame === frameState.frameNumber) { | |||
| return; | |||
| } | |||
| layer._cache.touch(tile); | |||
| tile.touchedFrame = frameState.frameNumber; | |||
| } | |||
| function updateVisibility(layer, tile, frameState) { | |||
| if (tile.updatedVisibilityFrame === frameState.frameNumber) { | |||
| return; | |||
| } | |||
| tile.updatedVisibilityFrame = frameState.frameNumber; | |||
| tile.updateVisibility(frameState, layer); | |||
| } | |||
| function updateTileVisibility(frameState, layer, tile) { | |||
| updateVisibility(layer, tile, frameState); | |||
| } | |||
| function updateMinimumMaximumPriority(layer, tile) { | |||
| layer._maximumPriority.distance = Math.max(tile.distanceToCamera, layer._maximumPriority.distance); | |||
| layer._minimumPriority.distance = Math.min(tile.distanceToCamera, layer._minimumPriority.distance); | |||
| layer._maximumPriority.depth = Math.max(tile.depth, layer._maximumPriority.depth); | |||
| layer._minimumPriority.depth = Math.min(tile.depth, layer._minimumPriority.depth); | |||
| layer._maximumPriority.foveatedFactor = Math.max(tile.foveatedFactor, layer._maximumPriority.foveatedFactor); | |||
| layer._minimumPriority.foveatedFactor = Math.min(tile.foveatedFactor, layer._minimumPriority.foveatedFactor); | |||
| layer._maximumPriority.pixel = Math.max(tile.pixel, layer._maximumPriority.pixel); | |||
| layer._minimumPriority.pixel = Math.min(tile.pixel, layer._minimumPriority.pixel); | |||
| } | |||
| function updateTile(frameState, layer, tile) { | |||
| updateTileVisibility(frameState, layer, tile); | |||
| tile.wasMinPriorityChild = false; | |||
| tile.priorityHolder = tile; | |||
| updateMinimumMaximumPriority(layer, tile); | |||
| tile.shouldSelect = false; | |||
| tile.selected = false; | |||
| } | |||
| function canTraverse(layer, tile) { | |||
| if (tile.children.length === 0) { | |||
| return false; | |||
| } | |||
| if(tile.lodRangeMode === RangeMode.Pixel){ | |||
| return tile.pixel / layer.lodRangeScale > tile.lodRangeData; | |||
| } | |||
| return tile.distanceToCamera * layer.lodRangeScale < tile.lodRangeData; | |||
| } | |||
| function traversal(layer, stack, frameState) { | |||
| while(stack.length) { | |||
| let tile = stack.pop(); | |||
| let parent = tile.parent; | |||
| let parentRefines = !Cesium.defined(parent) || parent.refines; | |||
| let refines = false; | |||
| if (canTraverse(layer, tile)) { | |||
| refines = updateChildren(layer, tile, stack, frameState) && parentRefines; | |||
| } | |||
| let stoppedRefining = !refines && parentRefines; | |||
| loadTile(layer, tile, frameState); | |||
| processTile(layer, tile, frameState); | |||
| if (stoppedRefining) { | |||
| selectTile(layer, tile, frameState); | |||
| } | |||
| touchTile(layer, tile, frameState); | |||
| tile.refines = refines; | |||
| } | |||
| } | |||
| function selectRootTiles(layer, stack, frameState) { | |||
| stack.length = 0; | |||
| for(let i = 0,j = layer._rootTiles.length;i < j;i++){ | |||
| let rootTile = layer._rootTiles[i]; | |||
| updateTile(frameState, layer, rootTile); | |||
| if(!rootTile.visible) { | |||
| continue ; | |||
| } | |||
| stack.push(rootTile); | |||
| } | |||
| } | |||
| function updatePriority(layer, frameState) { | |||
| let requestTiles = layer._requestTiles; | |||
| let length = requestTiles.length; | |||
| for (let i = 0; i < length; ++i) { | |||
| requestTiles[i].updatePriority(layer, frameState); | |||
| } | |||
| } | |||
| S3MLayerScheduler.prototype.schedule = function(layer, frameState) { | |||
| let stack = this._stack; | |||
| selectRootTiles(layer, stack, frameState); | |||
| traversal(layer, stack, frameState); | |||
| updatePriority(layer, frameState); | |||
| }; | |||
| export default S3MLayerScheduler; | |||
| @@ -0,0 +1,490 @@ | |||
| import ContentState from './Enum/ContentState.js' | |||
| import S3ModelParser from '../S3MParser/S3ModelParser.js' | |||
| import S3MContentParser from './S3MContentParser.js' | |||
| import RangeMode from './Enum/RangeMode.js' | |||
| const { Cesium } = DC.Namespace | |||
| function S3MTile( | |||
| layer, | |||
| parent, | |||
| boundingVolume, | |||
| fileName, | |||
| rangeData, | |||
| rangeMode | |||
| ) { | |||
| this.layer = layer | |||
| this.parent = parent | |||
| let path = fileName.replace(/\\/g, '/') | |||
| this.fileExtension = Cesium.getExtensionFromUri(fileName) | |||
| this.relativePath = getUrl(path, layer) | |||
| this.fileName = fileName | |||
| this.isLeafTile = rangeData === 0 | |||
| this.isRootTile = false | |||
| this.boundingVolume = this.createBoundingVolume( | |||
| boundingVolume, | |||
| layer.modelMatrix | |||
| ) | |||
| let baseResource = Cesium.Resource.createIfNeeded(layer._baseResource) | |||
| if (Cesium.defined(parent)) { | |||
| this.baseUri = parent.baseUri | |||
| } else { | |||
| let resource = new Cesium.Resource(path) | |||
| this.baseUri = resource.getBaseUri() | |||
| } | |||
| this.contentResource = baseResource.getDerivedResource({ | |||
| url: this.relativePath | |||
| }) | |||
| this.serverKey = Cesium.RequestScheduler.getServerKey( | |||
| this.contentResource.getUrlComponent() | |||
| ) | |||
| this.request = undefined | |||
| this.cacheNode = undefined | |||
| this.distanceToCamera = 0 | |||
| this.centerZDepth = 0 | |||
| this.pixel = 0 | |||
| this.depth = parent ? parent.depth + 1 : 0 | |||
| this.visibilityPlaneMask = 0 | |||
| this.visible = false | |||
| this.children = [] | |||
| this.renderEntities = [] | |||
| this.lodRangeData = Cesium.defaultValue(rangeData, 16) | |||
| this.lodRangeMode = Cesium.defaultValue(rangeMode, RangeMode.Pixel) | |||
| this.contentState = this.isLeafTile | |||
| ? ContentState.READY | |||
| : ContentState.UNLOADED | |||
| this.touchedFrame = 0 | |||
| this.requestedFrame = 0 | |||
| this.processFrame = 0 | |||
| this.selectedFrame = 0 | |||
| this.updatedVisibilityFrame = 0 | |||
| this.foveatedFactor = 0 | |||
| this.priority = 0 | |||
| this.priorityHolder = this | |||
| this.wasMinPriorityChild = false | |||
| this.shouldSelect = false | |||
| this.selected = false | |||
| this.finalResolution = true | |||
| this.refines = false | |||
| } | |||
| Object.defineProperties(S3MTile.prototype, { | |||
| renderable: { | |||
| get: function() { | |||
| let renderEntities = this.renderEntities | |||
| let len = renderEntities.length | |||
| if (len === 0) { | |||
| return false | |||
| } | |||
| for (let i = 0; i < len; i++) { | |||
| if (!renderEntities[i].ready) { | |||
| return false | |||
| } | |||
| } | |||
| return true | |||
| } | |||
| } | |||
| }) | |||
| let scratchScale = new Cesium.Cartesian3() | |||
| function createSphere(sphere, transform) { | |||
| let center = Cesium.Cartesian3.clone(sphere.center) | |||
| let radius = sphere.radius | |||
| center = Cesium.Matrix4.multiplyByPoint(transform, center, center) | |||
| let scale = Cesium.Matrix4.getScale(transform, scratchScale) | |||
| let maxScale = Cesium.Cartesian3.maximumComponent(scale) | |||
| radius *= maxScale | |||
| return new Cesium.TileBoundingSphere(center, radius) | |||
| } | |||
| function getUrl(fileName, layer) { | |||
| fileName = fileName.replace(/\+/g, '%2B') | |||
| let url = layer._basePath | |||
| let isRealspace = layer._basePath.indexOf('realspace') > -1 | |||
| if (!isRealspace) { | |||
| return fileName | |||
| } | |||
| let afterRealspace = url.replace(/(.*realspace)/, '') | |||
| let lastUrl = url | |||
| .replace(/\/rest\/realspace/g, '') | |||
| .replace(afterRealspace, '') | |||
| return ( | |||
| lastUrl + | |||
| '/rest/realspace' + | |||
| afterRealspace + | |||
| 'data/path/' + | |||
| fileName | |||
| .replace(/^\.*/, '') | |||
| .replace(/^\//, '') | |||
| .replace(/\/$/, '') | |||
| ) | |||
| } | |||
| function createBoundingBox(box, transform) { | |||
| let min = new Cesium.Cartesian3(box.min.x, box.min.y, box.min.z) | |||
| Cesium.Matrix4.multiplyByPoint(transform, min, min) | |||
| let max = new Cesium.Cartesian3(box.max.x, box.max.y, box.max.z) | |||
| Cesium.Matrix4.multiplyByPoint(transform, max, max) | |||
| let sphere = Cesium.BoundingSphere.fromCornerPoints( | |||
| min, | |||
| max, | |||
| new Cesium.BoundingSphere() | |||
| ) | |||
| let center = sphere.center | |||
| let radius = sphere.radius | |||
| let scale = Cesium.Matrix4.getScale(transform, scratchScale) | |||
| let maxScale = Cesium.Cartesian3.maximumComponent(scale) | |||
| radius *= maxScale | |||
| return new Cesium.TileBoundingSphere(center, radius) | |||
| } | |||
| S3MTile.prototype.createBoundingVolume = function(parameter, transform) { | |||
| if (Cesium.defined(parameter.sphere)) { | |||
| return createSphere(parameter.sphere, transform) | |||
| } else if (Cesium.defined(parameter.box)) { | |||
| return createBoundingBox(parameter.box, transform) | |||
| } | |||
| return undefined | |||
| } | |||
| S3MTile.prototype.canTraverse = function() { | |||
| if (this.children.length === 0 || this.isLeafTile) { | |||
| return false | |||
| } | |||
| if (!Cesium.defined(this.lodRangeData)) { | |||
| return true | |||
| } | |||
| return this.pixel > this.lodRangeData | |||
| } | |||
| function getBoundingVolume(tile, frameState) { | |||
| return tile.boundingVolume | |||
| } | |||
| S3MTile.prototype.getPixel = function(frameState) { | |||
| let boundingVolume = this.boundingVolume | |||
| let radius = boundingVolume.radius | |||
| let center = boundingVolume.center | |||
| let distance = Cesium.Cartesian3.distance( | |||
| frameState.camera.positionWC, | |||
| center | |||
| ) | |||
| let height = frameState.context.drawingBufferHeight | |||
| let theta = frameState.camera.frustum._fovy * 0.5 | |||
| let screenYPix = height * 0.5 | |||
| let lamat = screenYPix / Math.tan(theta) | |||
| return (lamat * radius) / distance | |||
| } | |||
| S3MTile.prototype.distanceToTile = function(frameState) { | |||
| let boundingVolume = getBoundingVolume(this, frameState) | |||
| return boundingVolume.distanceToCamera(frameState) | |||
| } | |||
| let scratchToTileCenter = new Cesium.Cartesian3() | |||
| S3MTile.prototype.distanceToTileCenter = function(frameState) { | |||
| const boundingVolume = getBoundingVolume(this, frameState) | |||
| const toCenter = Cesium.Cartesian3.subtract( | |||
| boundingVolume.center, | |||
| frameState.camera.positionWC, | |||
| scratchToTileCenter | |||
| ) | |||
| return Cesium.Cartesian3.dot(frameState.camera.directionWC, toCenter) | |||
| } | |||
| S3MTile.prototype.visibility = function(frameState, parentVisibilityPlaneMask) { | |||
| let boundingVolume = getBoundingVolume(this, frameState) | |||
| return frameState.cullingVolume.computeVisibilityWithPlaneMask( | |||
| boundingVolume, | |||
| parentVisibilityPlaneMask | |||
| ) | |||
| } | |||
| let scratchCartesian = new Cesium.Cartesian3() | |||
| function priorityDeferred(tile, frameState) { | |||
| let camera = frameState.camera | |||
| let boundingVolume = tile.boundingVolume | |||
| let radius = boundingVolume.radius | |||
| let scaledCameraDirection = Cesium.Cartesian3.multiplyByScalar( | |||
| camera.directionWC, | |||
| tile.centerZDepth, | |||
| scratchCartesian | |||
| ) | |||
| let closestPointOnLine = Cesium.Cartesian3.add( | |||
| camera.positionWC, | |||
| scaledCameraDirection, | |||
| scratchCartesian | |||
| ) | |||
| let toLine = Cesium.Cartesian3.subtract( | |||
| closestPointOnLine, | |||
| boundingVolume.center, | |||
| scratchCartesian | |||
| ) | |||
| let distanceToCenterLine = Cesium.Cartesian3.magnitude(toLine) | |||
| let notTouchingSphere = distanceToCenterLine > radius | |||
| if (notTouchingSphere) { | |||
| let toLineNormalized = Cesium.Cartesian3.normalize(toLine, scratchCartesian) | |||
| let scaledToLine = Cesium.Cartesian3.multiplyByScalar( | |||
| toLineNormalized, | |||
| radius, | |||
| scratchCartesian | |||
| ) | |||
| let closestOnSphere = Cesium.Cartesian3.add( | |||
| boundingVolume.center, | |||
| scaledToLine, | |||
| scratchCartesian | |||
| ) | |||
| let toClosestOnSphere = Cesium.Cartesian3.subtract( | |||
| closestOnSphere, | |||
| camera.positionWC, | |||
| scratchCartesian | |||
| ) | |||
| let toClosestOnSphereNormalize = Cesium.Cartesian3.normalize( | |||
| toClosestOnSphere, | |||
| scratchCartesian | |||
| ) | |||
| tile.foveatedFactor = | |||
| 1.0 - | |||
| Math.abs( | |||
| Cesium.Cartesian3.dot(camera.directionWC, toClosestOnSphereNormalize) | |||
| ) | |||
| } else { | |||
| tile.foveatedFactor = 0.0 | |||
| } | |||
| } | |||
| S3MTile.prototype.updateVisibility = function(frameState, layer) { | |||
| let parent = this.parent | |||
| let parentVisibilityPlaneMask = Cesium.defined(parent) | |||
| ? parent.visibilityPlaneMask | |||
| : Cesium.CullingVolume.MASK_INDETERMINATE | |||
| this.distanceToCamera = this.distanceToTile(frameState) | |||
| this.centerZDepth = this.distanceToTileCenter(frameState) | |||
| this.pixel = this.getPixel(frameState) | |||
| this.visibilityPlaneMask = this.visibility( | |||
| frameState, | |||
| parentVisibilityPlaneMask | |||
| ) | |||
| this.visible = | |||
| this.visibilityPlaneMask !== Cesium.CullingVolume.MASK_OUTSIDE && | |||
| this.distanceToCamera >= layer.visibleDistanceMin && | |||
| this.distanceToCamera <= layer.visibleDistanceMax | |||
| this.priorityDeferred = priorityDeferred(this, frameState) | |||
| } | |||
| function createPriorityFunction(tile) { | |||
| return function() { | |||
| return tile.priority | |||
| } | |||
| } | |||
| function getContentFailedFunction(tile) { | |||
| return function(error) { | |||
| tile.contentState = ContentState.FAILED | |||
| tile.contentReadyPromise.reject(error) | |||
| } | |||
| } | |||
| function createChildren(parent, datas) { | |||
| let layer = parent.layer | |||
| let length = datas.length | |||
| let minRangeData = Number.MAX_VALUE | |||
| let maxRangeData = 0 | |||
| let mode = RangeMode.Pixel | |||
| for (let i = 0; i < length; i++) { | |||
| let data = datas[i] | |||
| let boundingVolume = data.boundingVolume | |||
| let fileName = data.rangeDataList | |||
| fileName = parent.baseUri + fileName | |||
| let rangeData = data.rangeList | |||
| let rangeMode = data.rangeMode | |||
| let renderEntitieMap = data.geoMap | |||
| if (rangeData !== 0) { | |||
| let tile = new S3MTile( | |||
| layer, | |||
| parent, | |||
| boundingVolume, | |||
| fileName, | |||
| rangeData, | |||
| rangeMode | |||
| ) | |||
| parent.children.push(tile) | |||
| layer._cache.add(tile) | |||
| } | |||
| for (let geoName in renderEntitieMap) { | |||
| if (renderEntitieMap.hasOwnProperty(geoName)) { | |||
| parent.renderEntities.push(renderEntitieMap[geoName]) | |||
| } | |||
| } | |||
| minRangeData = Math.min(minRangeData, rangeData) | |||
| maxRangeData = Math.max(maxRangeData, rangeData) | |||
| mode = rangeMode | |||
| } | |||
| if (parent.isRootTile) { | |||
| parent.lodRangeData = | |||
| mode === RangeMode.Pixel ? minRangeData / 2 : maxRangeData * 2 | |||
| parent.lodRangeMode = mode | |||
| } | |||
| } | |||
| function contentReadyFunction(layer, tile, arrayBuffer) { | |||
| layer._cache.add(tile) | |||
| S3ModelParser.s3tc = layer.context.s3tc | |||
| S3ModelParser.pvrtc = layer.context.pvrtc | |||
| S3ModelParser.etc1 = layer.context.etc1 | |||
| let content = S3ModelParser.parseBuffer(arrayBuffer) | |||
| if (!content) { | |||
| tile.contentState = ContentState.FAILED | |||
| tile.contentReadyPromise.reject() | |||
| return | |||
| } | |||
| let data = S3MContentParser.parse(layer, content, tile) | |||
| createChildren(tile, data) | |||
| tile.selectedFrame = 0 | |||
| tile.contentState = ContentState.READY | |||
| tile.contentReadyPromise.resolve(content) | |||
| } | |||
| S3MTile.prototype.requestContent = function() { | |||
| let that = this | |||
| let layer = this.layer | |||
| let resource = this.contentResource.clone() | |||
| let request = new Cesium.Request({ | |||
| throttle: true, | |||
| throttleByServer: true, | |||
| type: Cesium.RequestType.TILES3D, | |||
| priorityFunction: createPriorityFunction(this), | |||
| serverKey: this.serverKey | |||
| }) | |||
| this.request = request | |||
| resource.request = request | |||
| let promise = resource.fetchArrayBuffer() | |||
| if (!Cesium.defined(promise)) { | |||
| return false | |||
| } | |||
| this.contentState = ContentState.LOADING | |||
| this.contentReadyPromise = Cesium.when.defer() | |||
| let contentFailedFunction = getContentFailedFunction(this) | |||
| promise | |||
| .then(function(arrayBuffer) { | |||
| if (that.isDestroyed()) { | |||
| contentFailedFunction() | |||
| return | |||
| } | |||
| contentReadyFunction(layer, that, arrayBuffer) | |||
| }) | |||
| .otherwise(function(error) { | |||
| if (request.state === Cesium.RequestState.CANCELLED) { | |||
| that.contentState = ContentState.UNLOADED | |||
| return | |||
| } | |||
| contentFailedFunction(error) | |||
| }) | |||
| return true | |||
| } | |||
| function priorityNormalizeAndClamp(value, minimum, maximum) { | |||
| return Math.max( | |||
| Cesium.Math.normalize(value, minimum, maximum) - Cesium.Math.EPSILON7, | |||
| 0.0 | |||
| ) | |||
| } | |||
| function isolateDigits(normalizedValue, numberOfDigits, leftShift) { | |||
| let scaled = normalizedValue * Math.pow(10, numberOfDigits) | |||
| let integer = parseInt(scaled) | |||
| return integer * Math.pow(10, leftShift) | |||
| } | |||
| S3MTile.prototype.updatePriority = function(layer, frameState) { | |||
| let minimumPriority = layer._minimumPriority | |||
| let maximumPriority = layer._maximumPriority | |||
| let leftShift = 4 | |||
| let digitsCount = 4 | |||
| let normalizedFoveatedFactor = priorityNormalizeAndClamp( | |||
| this.foveatedFactor, | |||
| minimumPriority.foveatedFactor, | |||
| maximumPriority.foveatedFactor | |||
| ) | |||
| let foveatedDigits = isolateDigits( | |||
| normalizedFoveatedFactor, | |||
| digitsCount, | |||
| leftShift | |||
| ) | |||
| leftShift = 8 | |||
| let normalizedPixel = priorityNormalizeAndClamp( | |||
| this.pixel, | |||
| minimumPriority.pixel, | |||
| maximumPriority.pixel | |||
| ) | |||
| let pixelDigits = isolateDigits(1.0 - normalizedPixel, digitsCount, leftShift) | |||
| leftShift = 0 | |||
| let distancePriority = priorityNormalizeAndClamp( | |||
| this.distanceToCamera, | |||
| minimumPriority.distance, | |||
| maximumPriority.distance | |||
| ) | |||
| let distanceDigit = isolateDigits(distancePriority, digitsCount, leftShift) | |||
| this.priority = foveatedDigits + pixelDigits + distanceDigit | |||
| } | |||
| S3MTile.prototype.update = function(frameState, layer) { | |||
| for (let i = 0, j = this.renderEntities.length; i < j; i++) { | |||
| this.renderEntities[i].update(frameState, layer) | |||
| } | |||
| } | |||
| S3MTile.prototype.free = function() { | |||
| this.contentState = ContentState.UNLOADED | |||
| this.request = undefined | |||
| this.cacheNode = undefined | |||
| this.priorityHolder = undefined | |||
| this.contentReadyPromise = undefined | |||
| this.priorityHolder = undefined | |||
| for (let i = 0, j = this.renderEntities.length; i < j; i++) { | |||
| this.renderEntities[i].destroy() | |||
| } | |||
| this.renderEntities.length = 0 | |||
| this.children.length = 0 | |||
| } | |||
| S3MTile.prototype.isDestroyed = function() { | |||
| return false | |||
| } | |||
| S3MTile.prototype.destroy = function() { | |||
| this.free() | |||
| return Cesium.destroyObject(this) | |||
| } | |||
| export default S3MTile | |||
| @@ -0,0 +1,421 @@ | |||
| import S3MTile from './S3MTile.js' | |||
| import S3MLayerScheduler from './S3MLayerScheduler.js' | |||
| import S3MLayerCache from './S3MLayerCache.js' | |||
| import OperationType from './Enum/OperationType.js' | |||
| import Style3D from './Style3D.js' | |||
| const { Cesium } = DC.Namespace | |||
| function S3MTilesLayer(options) { | |||
| options = Cesium.defaultValue(options, Cesium.defaultValue.EMPTY_OBJECT) | |||
| Cesium.Check.defined('options.url', options.url) | |||
| Cesium.Check.defined('options.context', options.context) | |||
| this.id = Cesium.createGuid() | |||
| this.name = options.name | |||
| this.context = options.context | |||
| this._url = undefined | |||
| this._basePath = undefined | |||
| this._baseResource = undefined | |||
| this.modelMatrix = new Cesium.Matrix4() | |||
| this.invModelMatrix = new Cesium.Matrix4() | |||
| this._visibleDistanceMax = Cesium.defaultValue( | |||
| options.maxVisibleDistance, | |||
| Number.MAX_VALUE | |||
| ) | |||
| this._visibleDistanceMin = Cesium.defaultValue( | |||
| options.minVisibleDistance, | |||
| 0.0 | |||
| ) | |||
| this._lodRangeScale = Cesium.defaultValue(options.lodRangeScale, 1.0) | |||
| this._selectedColor = new Cesium.Color(0.7, 0.7, 1.0, 1.0) | |||
| this.fileType = undefined | |||
| this._position = undefined | |||
| this._rectangle = undefined | |||
| this._rootTiles = [] | |||
| this._schuduler = new S3MLayerScheduler() | |||
| this._selections = [] | |||
| this._objsOperationList = {} | |||
| this._requestTiles = [] | |||
| this._processTiles = [] | |||
| this._selectedTiles = [] | |||
| this._cache = new S3MLayerCache() | |||
| this._maximumMemoryUsage = -1 | |||
| this._totalMemoryUsageInBytes = 0 | |||
| this._style3D = new Style3D() | |||
| this._maximumPriority = { | |||
| foveatedFactor: -Number.MAX_VALUE, | |||
| depth: -Number.MAX_VALUE, | |||
| distance: -Number.MAX_VALUE, | |||
| pixel: -Number.MAX_VALUE | |||
| } | |||
| this._minimumPriority = { | |||
| foveatedFactor: Number.MAX_VALUE, | |||
| depth: Number.MAX_VALUE, | |||
| distance: Number.MAX_VALUE, | |||
| pixel: Number.MAX_VALUE | |||
| } | |||
| this._readyPromise = Cesium.when.defer() | |||
| this.loadConfig(options.url) | |||
| } | |||
| Object.defineProperties(S3MTilesLayer.prototype, { | |||
| ready: { | |||
| get: function() { | |||
| return this._rootTiles.length > 0 | |||
| } | |||
| }, | |||
| readyPromise: { | |||
| get: function() { | |||
| return this._readyPromise | |||
| } | |||
| }, | |||
| rectangle: { | |||
| get: function() { | |||
| return this._rectangle | |||
| } | |||
| }, | |||
| visibleDistanceMax: { | |||
| get: function() { | |||
| return this._visibleDistanceMax | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.number('max visible distance', value) | |||
| this._visibleDistanceMax = value | |||
| } | |||
| }, | |||
| visibleDistanceMin: { | |||
| get: function() { | |||
| return this._visibleDistanceMin | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.number('min visible distance', value) | |||
| this._visibleDistanceMin = value | |||
| } | |||
| }, | |||
| lodRangeScale: { | |||
| get: function() { | |||
| return this._lodRangeScale | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.number('set layer lod range scale', value) | |||
| this._lodRangeScale = value | |||
| } | |||
| }, | |||
| totalMemoryUsageInBytes: { | |||
| get: function() { | |||
| return this._totalMemoryUsageInBytes | |||
| }, | |||
| set: function(value) { | |||
| this._totalMemoryUsageInBytes = value | |||
| } | |||
| }, | |||
| maximumMemoryUsage: { | |||
| get: function() { | |||
| return this._maximumMemoryUsage | |||
| }, | |||
| set: function(value) { | |||
| this._maximumMemoryUsage = value | |||
| } | |||
| }, | |||
| style3D: { | |||
| get: function() { | |||
| return this._style3D | |||
| }, | |||
| set: function(value) { | |||
| this._style3D = value | |||
| } | |||
| } | |||
| }) | |||
| // Cesium.Scene.prototype.hookPickFunc = Cesium.Scene.prototype.pick; | |||
| // | |||
| // Cesium.Scene.prototype.pick = function(windowPosition, width, height) { | |||
| // let picked = this.hookPickFunc(windowPosition, width, height); | |||
| // if (picked) { | |||
| // let isS3MTilesLayer = picked.primitive && picked.primitive instanceof S3MTilesLayer; | |||
| // if(isS3MTilesLayer){ | |||
| // picked.primitive.setSelection(picked.id); | |||
| // } | |||
| // } | |||
| // else{ | |||
| // for(let i = 0,j = this.primitives.length;i < j;i++){ | |||
| // let primitive = this.primitives.get(i); | |||
| // primitive instanceof S3MTilesLayer && primitive.releaseSelection(); | |||
| // } | |||
| // } | |||
| // | |||
| // return picked; | |||
| // }; | |||
| S3MTilesLayer.prototype.loadConfig = function(url) { | |||
| let that = this | |||
| Cesium.when(url) | |||
| .then(function(url) { | |||
| let basePath | |||
| let resource = Cesium.Resource.createIfNeeded(url) | |||
| basePath = resource.getBaseUri(true) | |||
| that._url = resource.url | |||
| that._basePath = basePath | |||
| that._baseResource = resource | |||
| return resource.fetchJson() | |||
| }) | |||
| .then(function(config) { | |||
| let extensions = config.extensions | |||
| that.fileType = extensions['s3m:FileType'] | |||
| let lon = config.position.x | |||
| let lat = config.position.y | |||
| let height = config.position.z | |||
| that._position = Cesium.Cartesian3.fromDegrees(lon, lat, height) | |||
| that.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame( | |||
| that._position | |||
| ) | |||
| that.invModelMatrix = Cesium.Matrix4.inverse( | |||
| that.modelMatrix, | |||
| that.invModelMatrix | |||
| ) | |||
| that._rectangle = Cesium.Rectangle.fromDegrees( | |||
| config.geoBounds.left, | |||
| config.geoBounds.bottom, | |||
| config.geoBounds.right, | |||
| config.geoBounds.top | |||
| ) | |||
| if (config.heightRange) { | |||
| that._minHeight = config.heightRange.min | |||
| that._maxHeight = config.heightRange.max | |||
| } | |||
| if (config.wDescript) { | |||
| let wDescript = config.wDescript.range | |||
| that._minWValue = wDescript.min | |||
| that._maxWValue = wDescript.max | |||
| } | |||
| for (let i = 0, len = config.tiles.length; i < len; i++) { | |||
| let fileName = config.tiles[i].url | |||
| let boundingVolume = { | |||
| box: config.tiles[i].boundingbox | |||
| } | |||
| let tile = new S3MTile(that, undefined, boundingVolume, fileName) | |||
| tile.isRootTile = true | |||
| that._cache.add(tile) | |||
| that._rootTiles.push(tile) | |||
| } | |||
| that._readyPromise.resolve(that) | |||
| }) | |||
| .otherwise(function(error) { | |||
| that._readyPromise.reject(error) | |||
| }) | |||
| } | |||
| S3MTilesLayer.prototype._tranverseRenderEntity = function(options, callback) { | |||
| let stack = [] | |||
| for (let i = 0, j = this._rootTiles.length; i < j; i++) { | |||
| let rootTile = this._rootTiles[i] | |||
| stack.push(rootTile) | |||
| } | |||
| while (stack.length) { | |||
| let tile = stack.pop() | |||
| for (let i = 0, j = tile.renderEntities.length; i < j; i++) { | |||
| const renderEntity = tile.renderEntities[i] | |||
| if (renderEntity.ready) { | |||
| callback(renderEntity, options) | |||
| } | |||
| } | |||
| for (let i = 0, j = tile.children.length; i < j; i++) { | |||
| stack.push(tile.children[i]) | |||
| } | |||
| } | |||
| } | |||
| function updateObjsOperationCallback(renderEntity, options) { | |||
| renderEntity.updateObjsOperation(options.ids, options) | |||
| } | |||
| S3MTilesLayer.prototype._updateObjsOperation = function(ids) { | |||
| this._tranverseRenderEntity( | |||
| { | |||
| ids: ids | |||
| }, | |||
| updateObjsOperationCallback | |||
| ) | |||
| } | |||
| S3MTilesLayer.prototype._setObjsOperationType = function(ids, operationType) { | |||
| Cesium.Check.defined('set Objs Operation ids', ids) | |||
| Cesium.Check.defined('set Objs Operation operationType', operationType) | |||
| if (!Array.isArray(ids)) { | |||
| ids = [ids] | |||
| } | |||
| let tmpArr = new Cesium.AssociativeArray() | |||
| let id | |||
| for (let i = 0, j = ids.length; i < j; i++) { | |||
| id = ids[i] | |||
| if (!Cesium.defined(id)) { | |||
| continue | |||
| } | |||
| let operation = Cesium.defaultValue(this._objsOperationList[id], 0) | |||
| if (operation === operationType) { | |||
| continue | |||
| } | |||
| operation = operation | operationType | |||
| this._objsOperationList[id] = operation | |||
| tmpArr.set(id, operation) | |||
| } | |||
| if (tmpArr.length > 0) { | |||
| this._updateObjsOperation(tmpArr._hash) | |||
| } | |||
| } | |||
| S3MTilesLayer.prototype._removeObjsOperationType = function( | |||
| ids, | |||
| operationType | |||
| ) { | |||
| Cesium.Check.defined('set Objs Operation ids', ids) | |||
| if (!Array.isArray(ids)) { | |||
| ids = [ids] | |||
| } | |||
| let nonOperationType = OperationType.ALL ^ operationType | |||
| let tmpArr = new Cesium.AssociativeArray() | |||
| let id | |||
| for (let i = 0, j = ids.length; i < j; i++) { | |||
| id = ids[i] | |||
| let operation = this._objsOperationList[id] | |||
| if (!Cesium.defined(operation)) { | |||
| continue | |||
| } | |||
| operation &= nonOperationType | |||
| if (operation === OperationType.RESET) { | |||
| delete this._objsOperationList[id] | |||
| } else { | |||
| this._objsOperationList[id] = operation | |||
| } | |||
| tmpArr.set(id, operation) | |||
| } | |||
| if (tmpArr.length > 0) { | |||
| this._updateObjsOperation(tmpArr._hash) | |||
| } | |||
| } | |||
| S3MTilesLayer.prototype.releaseSelection = function() { | |||
| if (this._selections.length < 1) { | |||
| return | |||
| } | |||
| this._removeObjsOperationType(this._selections, OperationType.SELECTED) | |||
| this._selections.length = 0 | |||
| } | |||
| S3MTilesLayer.prototype.setSelection = function(ids) { | |||
| Cesium.Check.defined('setSelection ids', ids) | |||
| if (!Array.isArray(ids)) { | |||
| ids = [ids] | |||
| } | |||
| this.releaseSelection() | |||
| this._selections = this._selections.concat(ids) | |||
| this._setObjsOperationType(ids, OperationType.SELECTED) | |||
| } | |||
| function sortRequestByPriority(a, b) { | |||
| return a.priority - b.priority | |||
| } | |||
| function requestTiles(layer) { | |||
| let requestTiles = layer._requestTiles | |||
| let length = requestTiles.length | |||
| requestTiles.sort(sortRequestByPriority) | |||
| for (let i = 0; i < length; ++i) { | |||
| let tile = requestTiles[i] | |||
| tile.requestContent() | |||
| } | |||
| } | |||
| function processTiles(layer, frameState) { | |||
| let tiles = layer._processTiles | |||
| let length = tiles.length | |||
| for (let i = 0; i < length; ++i) { | |||
| let tile = tiles[i] | |||
| tile.update(frameState, layer) | |||
| } | |||
| } | |||
| function updateTiles(layer, frameState) { | |||
| let selectedTiles = layer._selectedTiles | |||
| let length = selectedTiles.length | |||
| for (let i = 0; i < length; i++) { | |||
| selectedTiles[i].update(frameState, layer) | |||
| } | |||
| } | |||
| function unloadTile(layer, tile) { | |||
| tile.free() | |||
| } | |||
| function freeResource(layer) { | |||
| layer._cache.unloadTiles(layer, unloadTile) | |||
| } | |||
| S3MTilesLayer.prototype.prePassesUpdate = function(frameState) { | |||
| if (!this.ready) { | |||
| return | |||
| } | |||
| if (frameState.newFrame) { | |||
| this._cache.reset() | |||
| this._requestTiles.length = 0 | |||
| this._processTiles.length = 0 | |||
| this._selectedTiles.length = 0 | |||
| } | |||
| } | |||
| S3MTilesLayer.prototype.postPassesUpdate = function(frameState) { | |||
| if (!this.ready) { | |||
| return | |||
| } | |||
| freeResource(this) | |||
| } | |||
| S3MTilesLayer.prototype.update = function(frameState) { | |||
| if (!this.ready) { | |||
| return | |||
| } | |||
| this._schuduler.schedule(this, frameState) | |||
| requestTiles(this) | |||
| processTiles(this, frameState) | |||
| updateTiles(this, frameState) | |||
| } | |||
| S3MTilesLayer.prototype.isDestroyed = function() { | |||
| return false | |||
| } | |||
| S3MTilesLayer.prototype.destroy = function() { | |||
| this._cache.reset() | |||
| freeResource(this) | |||
| this._rootTiles.length = 0 | |||
| this._requestTiles.length = 0 | |||
| this._processTiles.length = 0 | |||
| this._selectedTiles.length = 0 | |||
| return Cesium.destroyObject(this) | |||
| } | |||
| export default S3MTilesLayer | |||
| @@ -0,0 +1,189 @@ | |||
| export default ` | |||
| #ifdef GL_OES_standard_derivatives | |||
| #extension GL_OES_standard_derivatives : enable | |||
| #endif | |||
| #ifdef GL_EXT_shader_texture_lod | |||
| #extension GL_EXT_shader_texture_lod : enable | |||
| #endif | |||
| uniform vec4 uDiffuseColor; | |||
| #ifdef TexCoord | |||
| varying vec4 vTexCoord; | |||
| #ifdef COMPUTE_TEXCOORD | |||
| uniform sampler2D uTexture; | |||
| uniform float uTexture0Width; | |||
| varying vec4 vTexCoordTransform; | |||
| varying vec4 vTexMatrix; | |||
| varying vec2 vIsRGBA; | |||
| #endif | |||
| #endif | |||
| varying vec4 vColor; | |||
| varying vec4 vSecondColor; | |||
| varying vec4 vPositionMC; | |||
| varying vec3 vPositionEC; | |||
| #ifdef VertexNormal | |||
| varying vec3 vNormalEC; | |||
| #endif | |||
| #ifdef TexCoord2 | |||
| uniform sampler2D uTexture2; | |||
| uniform float uTexture1Width; | |||
| varying vec4 vTexMatrix2; | |||
| #endif | |||
| #ifdef COMPUTE_TEXCOORD | |||
| void calculateMipLevel(in vec2 inTexCoord, in float vecTile, in float fMaxMip, inout float mipLevel) | |||
| { | |||
| vec2 dx = dFdx(inTexCoord * vecTile); | |||
| vec2 dy = dFdy(inTexCoord * vecTile); | |||
| float dotX = dot(dx, dx); | |||
| float dotY = dot(dy, dy); | |||
| float dMax = max(dotX, dotY); | |||
| float dMin = min(dotX, dotY); | |||
| float offset = (dMax - dMin) / (dMax + dMin); | |||
| offset = clamp(offset, 0.0, 1.0); | |||
| float d = dMax * (1.0 - offset) + dMin * offset; | |||
| mipLevel = 0.5 * log2(d); | |||
| mipLevel = clamp(mipLevel, 0.0, fMaxMip - 1.62); | |||
| } | |||
| void calculateTexCoord(in vec3 inTexCoord, in float scale, in float XTran, in float YTran, in float fTile, in float mipLevel, inout vec2 outTexCoord) | |||
| { | |||
| if(inTexCoord.z < -9000.0) | |||
| { | |||
| outTexCoord = inTexCoord.xy; | |||
| } | |||
| else | |||
| { | |||
| vec2 fTexCoord = fract(inTexCoord.xy); | |||
| float offset = 1.0 * pow(2.0, mipLevel) / fTile; | |||
| fTexCoord = clamp(fTexCoord, offset, 1.0 - offset); | |||
| outTexCoord.x = (fTexCoord.x + XTran) * scale; | |||
| outTexCoord.y = (fTexCoord.y + YTran) * scale; | |||
| } | |||
| } | |||
| vec4 getTexColorForS3M(sampler2D curTexture, vec3 oriTexCoord, float texTileWidth, float fMaxMipLev, float fTexCoordScale, vec2 vecTexCoordTranslate, float isRGBA) | |||
| { | |||
| vec4 color = vec4(1.0); | |||
| float mipLevel = 0.0; | |||
| #ifdef GL_OES_standard_derivatives | |||
| calculateMipLevel(oriTexCoord.xy, texTileWidth, fMaxMipLev, mipLevel); | |||
| #endif | |||
| vec2 realTexCoord; | |||
| calculateTexCoord(oriTexCoord, fTexCoordScale, vecTexCoordTranslate.x, vecTexCoordTranslate.y, texTileWidth, mipLevel, realTexCoord); | |||
| if(isRGBA > 0.5) | |||
| { | |||
| vec2 rgbTexCoord; | |||
| rgbTexCoord.x = (realTexCoord.x + vecTexCoordTranslate.x * fTexCoordScale) * 0.5; | |||
| rgbTexCoord.y = (realTexCoord.y + vecTexCoordTranslate.y * fTexCoordScale) * 0.5; | |||
| color = texture2D(curTexture, rgbTexCoord.xy, -10.0); | |||
| vec2 vecAlphaTexCoord; | |||
| vecAlphaTexCoord.x = rgbTexCoord.x; | |||
| vecAlphaTexCoord.y = rgbTexCoord.y + fTexCoordScale * 0.5; | |||
| color.a = texture2D(curTexture, vecAlphaTexCoord.xy, -10.0).r; | |||
| } | |||
| else | |||
| { | |||
| if(oriTexCoord.z < -9000.0) | |||
| { | |||
| color = texture2D(curTexture, realTexCoord.xy); | |||
| } | |||
| else | |||
| { | |||
| #ifdef GL_EXT_shader_texture_lod | |||
| color = texture2DLodEXT(curTexture, realTexCoord.xy, mipLevel); | |||
| #else | |||
| color = texture2D(curTexture, realTexCoord.xy, mipLevel); | |||
| #endif | |||
| } | |||
| } | |||
| return color; | |||
| } | |||
| vec4 getTextureColor() | |||
| { | |||
| if(vTexMatrix.z < 0.0) | |||
| { | |||
| return vec4(1.0); | |||
| } | |||
| float texTileWidth0 = vTexMatrix.z * uTexture0Width; | |||
| vec3 realTexCoord = vec3(vTexCoord.xy, vTexCoordTransform.x); | |||
| vec4 FColor = getTexColorForS3M(uTexture, realTexCoord, texTileWidth0, vTexMatrix.w, vTexMatrix.z, vTexMatrix.xy, vIsRGBA.x); | |||
| #ifdef TexCoord2 | |||
| float texTileWidth1 = vTexMatrix2.z * uTexture1Width; | |||
| realTexCoord = vec3(vTexCoord.zw, vTexCoordTransform.y); | |||
| vec4 SColor = getTexColorForS3M(uTexture2, realTexCoord, texTileWidth1, vTexMatrix2.w, vTexMatrix2.z, vTexMatrix2.xy, vIsRGBA.y); | |||
| SColor.r = clamp(SColor.r, 0.0, 1.0); | |||
| SColor.g = clamp(SColor.g, 0.0, 1.0); | |||
| SColor.b = clamp(SColor.b, 0.0, 1.0); | |||
| return FColor * SColor; | |||
| #else | |||
| return FColor; | |||
| #endif | |||
| } | |||
| #endif | |||
| vec4 SRGBtoLINEAR4(vec4 srgbIn) | |||
| { | |||
| #ifndef HDR | |||
| vec3 linearOut = pow(srgbIn.rgb, vec3(2.2)); | |||
| return vec4(linearOut, srgbIn.a); | |||
| #else | |||
| return srgbIn; | |||
| #endif | |||
| } | |||
| vec3 LINEARtoSRGB(vec3 linearIn) | |||
| { | |||
| #ifndef HDR | |||
| return pow(linearIn, vec3(1.0/2.2)); | |||
| #else | |||
| return linearIn; | |||
| #endif | |||
| } | |||
| vec3 applyTonemapping(vec3 linearIn) | |||
| { | |||
| #ifndef HDR | |||
| return czm_acesTonemapping(linearIn); | |||
| #else | |||
| return linearIn; | |||
| #endif | |||
| } | |||
| vec3 computeNormal(in vec3 oriVertex) | |||
| { | |||
| vec3 normal = cross(vec3(dFdx(oriVertex.x), dFdx(oriVertex.y), dFdx(oriVertex.z)), vec3(dFdy(oriVertex.x), dFdy(oriVertex.y), dFdy(oriVertex.z))); | |||
| normal = normalize(normal); | |||
| return normal; | |||
| } | |||
| void main() | |||
| { | |||
| if(vColor.a < 0.1) | |||
| { | |||
| discard; | |||
| } | |||
| vec4 baseColorWithAlpha = vColor; | |||
| #ifdef COMPUTE_TEXCOORD | |||
| baseColorWithAlpha *= SRGBtoLINEAR4(getTextureColor()); | |||
| #endif | |||
| if(baseColorWithAlpha.a < 0.1) | |||
| { | |||
| discard; | |||
| } | |||
| vec3 normal = vec3(0.0); | |||
| #ifdef VertexNormal | |||
| normal = normalize(vNormalEC); | |||
| #endif | |||
| normal = length(normal) > 0.1 ? normal : computeNormal(vPositionMC.xyz); | |||
| vec3 color = baseColorWithAlpha.rgb; | |||
| vec3 dirVectorEC = normalize(czm_lightDirectionEC); | |||
| float dotProduct = dot( normal, dirVectorEC ); | |||
| float dirDiffuseWeight = max( dotProduct, 0.0 ); | |||
| dirDiffuseWeight = dirDiffuseWeight * 0.5 + 0.5; | |||
| color += color * uDiffuseColor.rgb * dirDiffuseWeight; | |||
| #ifdef TexCoord | |||
| color = LINEARtoSRGB(color); | |||
| #endif | |||
| gl_FragColor = vec4(color, baseColorWithAlpha.a); | |||
| } | |||
| `; | |||
| @@ -0,0 +1,103 @@ | |||
| export default ` | |||
| #ifdef GL_OES_standard_derivatives | |||
| #extension GL_OES_standard_derivatives : enable | |||
| #endif | |||
| #ifdef GL_EXT_shader_texture_lod | |||
| #extension GL_EXT_shader_texture_lod : enable | |||
| #endif | |||
| #ifdef TexCoord | |||
| uniform sampler2D uTexture; | |||
| uniform float uTexture0Width; | |||
| varying vec4 vTexCoord; | |||
| varying vec4 vTexCoordTransform; | |||
| varying vec4 vTexMatrix; | |||
| #endif | |||
| #ifdef VertexColor | |||
| varying vec4 vColor; | |||
| #endif | |||
| #ifdef TexCoord | |||
| void calculateMipLevel(in vec2 inTexCoord, in float vecTile, in float fMaxMip, inout float mipLevel) | |||
| { | |||
| vec2 dx = dFdx(inTexCoord * vecTile); | |||
| vec2 dy = dFdy(inTexCoord * vecTile); | |||
| float dotX = dot(dx, dx); | |||
| float dotY = dot(dy, dy); | |||
| float dMax = max(dotX, dotY); | |||
| float dMin = min(dotX, dotY); | |||
| float offset = (dMax - dMin) / (dMax + dMin); | |||
| offset = clamp(offset, 0.0, 1.0); | |||
| float d = dMax * (1.0 - offset) + dMin * offset; | |||
| mipLevel = 0.5 * log2(d); | |||
| mipLevel = clamp(mipLevel, 0.0, fMaxMip - 1.62); | |||
| } | |||
| void calculateTexCoord(in vec3 inTexCoord, in float scale, in float XTran, in float YTran, in float fTile, in float mipLevel, inout vec2 outTexCoord) | |||
| { | |||
| if(inTexCoord.z < -9000.0) | |||
| { | |||
| outTexCoord = inTexCoord.xy; | |||
| } | |||
| else | |||
| { | |||
| vec2 fTexCoord = fract(inTexCoord.xy); | |||
| float offset = 1.0 * pow(2.0, mipLevel) / fTile; | |||
| fTexCoord = clamp(fTexCoord, offset, 1.0 - offset); | |||
| outTexCoord.x = (fTexCoord.x + XTran) * scale; | |||
| outTexCoord.y = (fTexCoord.y + YTran) * scale; | |||
| } | |||
| } | |||
| vec4 getTexColorForS3M(sampler2D curTexture, vec3 oriTexCoord, float texTileWidth, float fMaxMipLev, float fTexCoordScale, vec2 vecTexCoordTranslate) | |||
| { | |||
| vec4 color = vec4(1.0); | |||
| float mipLevel = 0.0; | |||
| #ifdef GL_OES_standard_derivatives | |||
| calculateMipLevel(oriTexCoord.xy, texTileWidth, fMaxMipLev, mipLevel); | |||
| #endif | |||
| vec2 realTexCoord; | |||
| calculateTexCoord(oriTexCoord, fTexCoordScale, vecTexCoordTranslate.x, vecTexCoordTranslate.y, texTileWidth, mipLevel, realTexCoord); | |||
| if(oriTexCoord.z < -9000.0) | |||
| { | |||
| color = texture2D(curTexture, realTexCoord.xy); | |||
| } | |||
| else | |||
| { | |||
| #ifdef GL_EXT_shader_texture_lod | |||
| color = texture2DLodEXT(curTexture, realTexCoord.xy, mipLevel); | |||
| #else | |||
| color = texture2D(curTexture, realTexCoord.xy, mipLevel); | |||
| #endif | |||
| } | |||
| return color; | |||
| } | |||
| vec4 getTextureColor() | |||
| { | |||
| if(vTexMatrix.z < 0.0) | |||
| { | |||
| return vec4(1.0); | |||
| } | |||
| float texTileWidth0 = vTexMatrix.z * uTexture0Width; | |||
| vec3 realTexCoord = vec3(vTexCoord.xy, vTexCoordTransform.x); | |||
| return getTexColorForS3M(uTexture, realTexCoord, texTileWidth0, vTexMatrix.w, vTexMatrix.z, vTexMatrix.xy); | |||
| } | |||
| #endif | |||
| void main() | |||
| { | |||
| vec4 baseColorWithAlpha = vec4(1.0); | |||
| #ifdef VertexColor | |||
| vec4 baseColorWithAlpha = vColor; | |||
| #endif | |||
| #ifdef TexCoord | |||
| baseColorWithAlpha *= getTextureColor(); | |||
| #endif | |||
| gl_FragColor = baseColorWithAlpha; | |||
| } | |||
| `; | |||
| @@ -0,0 +1,57 @@ | |||
| export default ` | |||
| attribute vec4 aPosition; | |||
| attribute vec4 aColor; | |||
| #ifdef TexCoord | |||
| attribute vec4 aTexCoord0; | |||
| uniform float uTexture0Width; | |||
| varying vec4 vTexCoord; | |||
| varying vec4 vTexMatrix; | |||
| varying vec4 vTexCoordTransform; | |||
| #endif | |||
| #ifdef VertexColor | |||
| varying vec4 vColor; | |||
| #endif | |||
| const float SHIFT_LEFT8 = 256.0; | |||
| const float SHIFT_RIGHT8 = 1.0 / 256.0; | |||
| const float SHIFT_RIGHT4 = 1.0 / 16.0; | |||
| const float SHIFT_LEFT4 = 16.0; | |||
| void getTextureMatrixFromZValue(in float nZ, inout float XTran, inout float YTran, inout float scale) | |||
| { | |||
| if(nZ <= 0.0) | |||
| { | |||
| return; | |||
| } | |||
| float nDel8 = floor(nZ * SHIFT_RIGHT8); | |||
| float nDel16 = floor(nDel8 * SHIFT_RIGHT8); | |||
| float nDel20 = floor(nDel16 * SHIFT_RIGHT4); | |||
| YTran = nZ - nDel8 * SHIFT_LEFT8; | |||
| XTran = nDel8 - nDel16 * SHIFT_LEFT8; | |||
| float nLevel = nDel16 - nDel20 * SHIFT_LEFT4; | |||
| scale = 1.0 / pow(2.0, nLevel); | |||
| } | |||
| void main() | |||
| { | |||
| #ifdef TexCoord | |||
| vTexCoord.xy = aTexCoord0.xy; | |||
| vTexMatrix = vec4(0.0,0.0,1.0,0.0); | |||
| vTexCoordTransform.x = aTexCoord0.z; | |||
| if(vTexCoordTransform.x < -90000.0) | |||
| { | |||
| vTexMatrix.z = -1.0; | |||
| } | |||
| getTextureMatrixFromZValue(floor(vTexCoordTransform.x), vTexMatrix.x, vTexMatrix.y, vTexMatrix.z); | |||
| vTexMatrix.w = log2(uTexture0Width * vTexMatrix.z); | |||
| #endif | |||
| vec4 vertexPos = aPosition; | |||
| #ifdef VertexColor | |||
| vColor = aColor; | |||
| #endif | |||
| gl_Position = czm_modelViewProjection * vec4(vertexPos.xyz, 1.0); | |||
| } | |||
| `; | |||
| @@ -0,0 +1,159 @@ | |||
| export default ` | |||
| attribute vec4 aPosition; | |||
| #ifdef VertexColor | |||
| attribute vec4 aColor; | |||
| #endif | |||
| #ifdef VertexNormal | |||
| attribute vec3 aNormal; | |||
| #endif | |||
| #ifdef Instance | |||
| attribute float instanceId; | |||
| #else | |||
| attribute float batchId; | |||
| #endif | |||
| #ifdef TexCoord | |||
| attribute vec4 aTexCoord0; | |||
| varying vec4 vTexCoord; | |||
| uniform mat4 uTexMatrix; | |||
| #ifdef COMPUTE_TEXCOORD | |||
| uniform float uTexture0Width; | |||
| varying vec4 vTexMatrix; | |||
| varying vec4 vTexCoordTransform; | |||
| varying vec2 vIsRGBA; | |||
| #endif | |||
| #endif | |||
| #ifdef TexCoord2 | |||
| attribute vec4 aTexCoord1; | |||
| uniform float uTexture1Width; | |||
| varying vec4 vTexMatrix2; | |||
| #endif | |||
| #ifdef InstanceBim | |||
| attribute vec4 uv2; | |||
| attribute vec4 uv3; | |||
| attribute vec4 uv4; | |||
| attribute vec4 secondary_colour; | |||
| attribute vec4 uv6; | |||
| #endif | |||
| uniform vec4 uFillForeColor; | |||
| uniform vec4 uSelectedColor; | |||
| varying vec4 vSecondColor; | |||
| varying vec4 vPositionMC; | |||
| varying vec3 vPositionEC; | |||
| #ifdef VertexNormal | |||
| varying vec3 vNormalEC; | |||
| #endif | |||
| varying vec4 vColor; | |||
| const float SHIFT_LEFT8 = 256.0; | |||
| const float SHIFT_RIGHT8 = 1.0 / 256.0; | |||
| const float SHIFT_RIGHT4 = 1.0 / 16.0; | |||
| const float SHIFT_LEFT4 = 16.0; | |||
| void getTextureMatrixFromZValue(in float nZ, inout float XTran, inout float YTran, inout float scale, inout float isRGBA) | |||
| { | |||
| if(nZ <= 0.0) | |||
| { | |||
| return; | |||
| } | |||
| float nDel8 = floor(nZ * SHIFT_RIGHT8); | |||
| float nDel16 = floor(nDel8 * SHIFT_RIGHT8); | |||
| float nDel20 = floor(nDel16 * SHIFT_RIGHT4); | |||
| isRGBA = floor(nDel20); | |||
| YTran = nZ - nDel8 * SHIFT_LEFT8; | |||
| XTran = nDel8 - nDel16 * SHIFT_LEFT8; | |||
| float nLevel = nDel16 - nDel20 * SHIFT_LEFT4; | |||
| scale = 1.0 / pow(2.0, nLevel); | |||
| } | |||
| void operation(vec4 operationType, vec4 color, vec4 selectedColor, inout vec4 vertexColor) | |||
| { | |||
| float right_2 = operationType.x * 0.5; | |||
| float right_4 = right_2 * 0.5; | |||
| float right_8 = right_4 * 0.5; | |||
| float right_16 = right_8 * 0.5; | |||
| float isSetColor = fract(right_2); | |||
| if(isSetColor > 0.1) | |||
| { | |||
| vertexColor *= color; | |||
| } | |||
| float isPicked = fract(floor(right_2)* 0.5); | |||
| if(isPicked > 0.1) | |||
| { | |||
| vertexColor *= selectedColor; | |||
| } | |||
| float isHide = fract(floor(right_4)* 0.5); | |||
| if(isHide > 0.1) | |||
| { | |||
| vertexColor.a = 0.0; | |||
| } | |||
| } | |||
| void main() | |||
| { | |||
| #ifdef TexCoord | |||
| vTexCoord.xy = aTexCoord0.xy; | |||
| #ifdef COMPUTE_TEXCOORD | |||
| vTexMatrix = vec4(0.0,0.0,1.0,0.0); | |||
| vIsRGBA.x = 0.0; | |||
| vTexCoordTransform.x = aTexCoord0.z; | |||
| if(vTexCoordTransform.x < -90000.0) | |||
| { | |||
| vTexMatrix.z = -1.0; | |||
| } | |||
| getTextureMatrixFromZValue(floor(vTexCoordTransform.x), vTexMatrix.x, vTexMatrix.y, vTexMatrix.z, vIsRGBA.x); | |||
| vTexMatrix.w = log2(uTexture0Width * vTexMatrix.z); | |||
| #endif | |||
| #endif | |||
| #ifdef TexCoord2 | |||
| vTexCoord.zw = aTexCoord1.xy; | |||
| vTexMatrix2 = vec4(0.0,0.0,1.0,0.0); | |||
| vIsRGBA.y = 0.0; | |||
| vTexCoordTransform.y = aTexCoord1.z; | |||
| if(vTexCoordTransform.y < -90000.0) | |||
| { | |||
| vTexMatrix2.z = -1.0; | |||
| } | |||
| getTextureMatrixFromZValue(floor(vTexCoordTransform.y), vTexMatrix2.x, vTexMatrix2.y, vTexMatrix2.z, vIsRGBA.y); | |||
| vTexMatrix2.w = log2(uTexture1Width * vTexMatrix.z); | |||
| #endif | |||
| vec4 vertexPos = aPosition; | |||
| vec4 vertexColor = uFillForeColor; | |||
| #ifdef VertexColor | |||
| vertexColor *= aColor; | |||
| #endif | |||
| #ifdef VertexNormal | |||
| vec3 normal = aNormal; | |||
| #endif | |||
| #ifdef InstanceBim | |||
| mat4 worldMatrix; | |||
| worldMatrix[0] = uv2; | |||
| worldMatrix[1] = uv3; | |||
| worldMatrix[2] = uv4; | |||
| worldMatrix[3] = vec4(0, 0, 0, 1); | |||
| vertexPos = vec4(vertexPos.xyz,1.0) * worldMatrix; | |||
| vertexColor *= secondary_colour; | |||
| #endif | |||
| #ifdef Instance | |||
| float index = instanceId; | |||
| #else | |||
| float index = batchId; | |||
| #endif | |||
| vec4 operationType = batchTable_operation(index); | |||
| operation(operationType, vec4(1.0), uSelectedColor, vertexColor); | |||
| vSecondColor = batchTable_pickColor(index); | |||
| vec4 positionMC = vec4(vertexPos.xyz, 1.0); | |||
| vColor = vertexColor; | |||
| #ifdef VertexNormal | |||
| vNormalEC = czm_normal * normal; | |||
| #endif | |||
| vPositionMC = positionMC; | |||
| vPositionEC = (czm_modelView * positionMC).xyz; | |||
| gl_Position = czm_modelViewProjection * vec4(vertexPos.xyz, 1.0); | |||
| } | |||
| `; | |||
| @@ -0,0 +1,82 @@ | |||
| const { Cesium } = DC.Namespace | |||
| function Style3D() { | |||
| this._fillForeColor = new Cesium.Color() | |||
| this._lineColor = new Cesium.Color() | |||
| this._lineWidth = 1.0 | |||
| this._bottomAltitude = 0 | |||
| this._pointSize = 1.0 | |||
| this._pointColor = new Cesium.Color() | |||
| } | |||
| Object.defineProperties(Style3D.prototype, { | |||
| fillForeColor: { | |||
| get: function() { | |||
| return this._fillForeColor | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.object('fillForeColor value', value) | |||
| Cesium.Color.clone(value, this._fillForeColor) | |||
| } | |||
| }, | |||
| bottomAltitude: { | |||
| get: function() { | |||
| return this._bottomAltitude | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.number('bottomAltitude value', value) | |||
| if (this._bottomAltitude !== value) { | |||
| this._bottomAltitude = value | |||
| this._dirty = true | |||
| } | |||
| } | |||
| }, | |||
| altitudeMode: { | |||
| get: function() { | |||
| return this._altitudeMode | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.number('altitudeMode value', value) | |||
| this._altitudeMode = value | |||
| } | |||
| }, | |||
| lineColor: { | |||
| get: function() { | |||
| return this._lineColor | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.object('line color', value) | |||
| Cesium.Color.clone(value, this._lineColor) | |||
| } | |||
| }, | |||
| lineWidth: { | |||
| get: function() { | |||
| return this._lineWidth | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.number('line width', value) | |||
| this._lineWidth = value | |||
| } | |||
| }, | |||
| pointSize: { | |||
| get: function() { | |||
| return this._pointSize | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.number('point size', value) | |||
| this._pointSize = value | |||
| } | |||
| }, | |||
| pointColor: { | |||
| get: function() { | |||
| return this._pointColor | |||
| }, | |||
| set: function(value) { | |||
| Cesium.Check.typeOf.object('point color', value) | |||
| Cesium.Color.clone(value, this._pointColor) | |||
| } | |||
| } | |||
| }) | |||
| export default Style3D | |||
| @@ -0,0 +1,15 @@ | |||
| /** | |||
| * @Author: Caven | |||
| * @Date: 2022-02-20 13:46:53 | |||
| */ | |||
| import { Cesium } from '@dc-modules/namespace' | |||
| import State from '@dc-modules/state/State' | |||
| import { Layer } from '@dc-modules/layer' | |||
| import S3MTilesLayer from 's3m-lib/S3MTiles/S3MTilesLayer' | |||
| class S3MLayer extends Layer { | |||
| constructor(id, url) { | |||
| super(id) | |||
| } | |||
| } | |||
| @@ -0,0 +1,203 @@ | |||
| Copyright (c) 2019-present Caven Chen | |||
| Apache License | |||
| Version 2.0, January 2004 | |||
| http://www.apache.org/licenses/ | |||
| TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | |||
| 1. Definitions. | |||
| "License" shall mean the terms and conditions for use, reproduction, | |||
| and distribution as defined by Sections 1 through 9 of this document. | |||
| "Licensor" shall mean the copyright owner or entity authorized by | |||
| the copyright owner that is granting the License. | |||
| "Legal Entity" shall mean the union of the acting entity and all | |||
| other entities that control, are controlled by, or are under common | |||
| control with that entity. For the purposes of this definition, | |||
| "control" means (i) the power, direct or indirect, to cause the | |||
| direction or management of such entity, whether by contract or | |||
| otherwise, or (ii) ownership of fifty percent (50%) or more of the | |||
| outstanding shares, or (iii) beneficial ownership of such entity. | |||
| "You" (or "Your") shall mean an individual or Legal Entity | |||
| exercising permissions granted by this License. | |||
| "Source" form shall mean the preferred form for making modifications, | |||
| including but not limited to software source code, documentation | |||
| source, and configuration files. | |||
| "Object" form shall mean any form resulting from mechanical | |||
| transformation or translation of a Source form, including but | |||
| not limited to compiled object code, generated documentation, | |||
| and conversions to other media types. | |||
| "Work" shall mean the work of authorship, whether in Source or | |||
| Object form, made available under the License, as indicated by a | |||
| copyright notice that is included in or attached to the work | |||
| (an example is provided in the Appendix below). | |||
| "Derivative Works" shall mean any work, whether in Source or Object | |||
| form, that is based on (or derived from) the Work and for which the | |||
| editorial revisions, annotations, elaborations, or other modifications | |||
| represent, as a whole, an original work of authorship. For the purposes | |||
| of this License, Derivative Works shall not include works that remain | |||
| separable from, or merely link (or bind by name) to the interfaces of, | |||
| the Work and Derivative Works thereof. | |||
| "Contribution" shall mean any work of authorship, including | |||
| the original version of the Work and any modifications or additions | |||
| to that Work or Derivative Works thereof, that is intentionally | |||
| submitted to Licensor for inclusion in the Work by the copyright owner | |||
| or by an individual or Legal Entity authorized to submit on behalf of | |||
| the copyright owner. For the purposes of this definition, "submitted" | |||
| means any form of electronic, verbal, or written communication sent | |||
| to the Licensor or its representatives, including but not limited to | |||
| communication on electronic mailing lists, source code control systems, | |||
| and issue tracking systems that are managed by, or on behalf of, the | |||
| Licensor for the purpose of discussing and improving the Work, but | |||
| excluding communication that is conspicuously marked or otherwise | |||
| designated in writing by the copyright owner as "Not a Contribution." | |||
| "Contributor" shall mean Licensor and any individual or Legal Entity | |||
| on behalf of whom a Contribution has been received by Licensor and | |||
| subsequently incorporated within the Work. | |||
| 2. Grant of Copyright License. Subject to the terms and conditions of | |||
| this License, each Contributor hereby grants to You a perpetual, | |||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
| copyright license to reproduce, prepare Derivative Works of, | |||
| publicly display, publicly perform, sublicense, and distribute the | |||
| Work and such Derivative Works in Source or Object form. | |||
| 3. Grant of Patent License. Subject to the terms and conditions of | |||
| this License, each Contributor hereby grants to You a perpetual, | |||
| worldwide, non-exclusive, no-charge, royalty-free, irrevocable | |||
| (except as stated in this section) patent license to make, have made, | |||
| use, offer to sell, sell, import, and otherwise transfer the Work, | |||
| where such license applies only to those patent claims licensable | |||
| by such Contributor that are necessarily infringed by their | |||
| Contribution(s) alone or by combination of their Contribution(s) | |||
| with the Work to which such Contribution(s) was submitted. If You | |||
| institute patent litigation against any entity (including a | |||
| cross-claim or counterclaim in a lawsuit) alleging that the Work | |||
| or a Contribution incorporated within the Work constitutes direct | |||
| or contributory patent infringement, then any patent licenses | |||
| granted to You under this License for that Work shall terminate | |||
| as of the date such litigation is filed. | |||
| 4. Redistribution. You may reproduce and distribute copies of the | |||
| Work or Derivative Works thereof in any medium, with or without | |||
| modifications, and in Source or Object form, provided that You | |||
| meet the following conditions: | |||
| (a) You must give any other recipients of the Work or | |||
| Derivative Works a copy of this License; and | |||
| (b) You must cause any modified files to carry prominent notices | |||
| stating that You changed the files; and | |||
| (c) You must retain, in the Source form of any Derivative Works | |||
| that You distribute, all copyright, patent, trademark, and | |||
| attribution notices from the Source form of the Work, | |||
| excluding those notices that do not pertain to any part of | |||
| the Derivative Works; and | |||
| (d) If the Work includes a "NOTICE" text file as part of its | |||
| distribution, then any Derivative Works that You distribute must | |||
| include a readable copy of the attribution notices contained | |||
| within such NOTICE file, excluding those notices that do not | |||
| pertain to any part of the Derivative Works, in at least one | |||
| of the following places: within a NOTICE text file distributed | |||
| as part of the Derivative Works; within the Source form or | |||
| documentation, if provided along with the Derivative Works; or, | |||
| within a display generated by the Derivative Works, if and | |||
| wherever such third-party notices normally appear. The contents | |||
| of the NOTICE file are for informational purposes only and | |||
| do not modify the License. You may add Your own attribution | |||
| notices within Derivative Works that You distribute, alongside | |||
| or as an addendum to the NOTICE text from the Work, provided | |||
| that such additional attribution notices cannot be construed | |||
| as modifying the License. | |||
| You may add Your own copyright statement to Your modifications and | |||
| may provide additional or different license terms and conditions | |||
| for use, reproduction, or distribution of Your modifications, or | |||
| for any such Derivative Works as a whole, provided Your use, | |||
| reproduction, and distribution of the Work otherwise complies with | |||
| the conditions stated in this License. | |||
| 5. Submission of Contributions. Unless You explicitly state otherwise, | |||
| any Contribution intentionally submitted for inclusion in the Work | |||
| by You to the Licensor shall be under the terms and conditions of | |||
| this License, without any additional terms or conditions. | |||
| Notwithstanding the above, nothing herein shall supersede or modify | |||
| the terms of any separate license agreement you may have executed | |||
| with Licensor regarding such Contributions. | |||
| 6. Trademarks. This License does not grant permission to use the trade | |||
| names, trademarks, service marks, or product names of the Licensor, | |||
| except as required for reasonable and customary use in describing the | |||
| origin of the Work and reproducing the content of the NOTICE file. | |||
| 7. Disclaimer of Warranty. Unless required by applicable law or | |||
| agreed to in writing, Licensor provides the Work (and each | |||
| Contributor provides its Contributions) on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||
| implied, including, without limitation, any warranties or conditions | |||
| of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | |||
| PARTICULAR PURPOSE. You are solely responsible for determining the | |||
| appropriateness of using or redistributing the Work and assume any | |||
| risks associated with Your exercise of permissions under this License. | |||
| 8. Limitation of Liability. In no event and under no legal theory, | |||
| whether in tort (including negligence), contract, or otherwise, | |||
| unless required by applicable law (such as deliberate and grossly | |||
| negligent acts) or agreed to in writing, shall any Contributor be | |||
| liable to You for damages, including any direct, indirect, special, | |||
| incidental, or consequential damages of any character arising as a | |||
| result of this License or out of the use or inability to use the | |||
| Work (including but not limited to damages for loss of goodwill, | |||
| work stoppage, computer failure or malfunction, or any and all | |||
| other commercial damages or losses), even if such Contributor | |||
| has been advised of the possibility of such damages. | |||
| 9. Accepting Warranty or Additional Liability. While redistributing | |||
| the Work or Derivative Works thereof, You may choose to offer, | |||
| and charge a fee for, acceptance of support, warranty, indemnity, | |||
| or other liability obligations and/or rights consistent with this | |||
| License. However, in accepting such obligations, You may act only | |||
| on Your own behalf and on Your sole responsibility, not on behalf | |||
| of any other Contributor, and only if You agree to indemnify, | |||
| defend, and hold each Contributor harmless for any liability | |||
| incurred by, or claims asserted against, such Contributor by reason | |||
| of your accepting any such warranty or additional liability. | |||
| END OF TERMS AND CONDITIONS | |||
| APPENDIX: How to apply the Apache License to your work. | |||
| To apply the Apache License to your work, attach the following | |||
| boilerplate notice, with the fields enclosed by brackets "[]" | |||
| replaced with your own identifying information. (Don't include | |||
| the brackets!) The text should be enclosed in the appropriate | |||
| comment syntax for the file format. We also recommend that a | |||
| file or class name and description of purpose be included on the | |||
| same "printed page" as the copyright notice for easier | |||
| identification within third-party archives. | |||
| Copyright (c) 2019-present Caven Chen | |||
| Licensed under the Apache License, Version 2.0 (the "License"); | |||
| you may not use this file except in compliance with the License. | |||
| You may obtain a copy of the License at | |||
| http://www.apache.org/licenses/LICENSE-2.0 | |||
| Unless required by applicable law or agreed to in writing, software | |||
| distributed under the License is distributed on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| See the License for the specific language governing permissions and | |||
| limitations under the License. | |||
| @@ -0,0 +1,217 @@ | |||
| # DC-SDK | |||
| <p> | |||
| <img src="https://img.shields.io/github/workflow/status/dvgis/dc-sdk/build"/> | |||
| <img src="https://img.shields.io/badge/license-Apache%202-blue"/> | |||
| <a href="https://www.npmjs.com/package/@dvgis/dc-sdk" target="_blank"> | |||
| <img src="https://img.shields.io/npm/v/@dvgis/dc-sdk?color=orange&logo=npm" /> | |||
| </a> | |||
| <a href="https://www.npmjs.com/package/@dvgis/dc-sdk" target="_blank"> | |||
| <img src="https://img.shields.io/npm/dt/@dvgis/dc-sdk?logo=npm"/> | |||
| </a> | |||
| <a href="https://resource.dvgis.cn/dc-docs/v2.x" target="_blank"> | |||
| <img src="https://img.shields.io/badge/docs-online-yellow.svg"/> | |||
| </a> | |||
| <a href="http://dc.dvgis.cn" target="_blank"> | |||
| <img src="https://img.shields.io/badge/demo-online-red.svg"/> | |||
| </a> | |||
| </p> | |||
| [**🇨🇳 中文**](./README_zh.md) | [**🇬🇧English**](./README.md) | |||
| `DC-SDK` is based on the open source project `Cesium` for the second development of two three-dimensional `WebGis` application framework , the framework optimizes the use of `Cesium` and adds some additional features , designed for developers to quickly build `WebGis` application. | |||
| ```warning | |||
| Tips:This SDK is JS+GIS framework package. Developers need to have some front-end technology and GIS related technology | |||
| ``` | |||
| ## Installation | |||
| `NPM / YARN` **_`(Recommend)`_** | |||
| Installing with NPM or YARN is recommended and it works seamlessly with webpack. | |||
| ```shell | |||
| yarn add @dvgis/dc-sdk | |||
| ------------------------- | |||
| npm install @dvgis/dc-sdk | |||
| ``` | |||
| ```js | |||
| import DC from '@dvgis/dc-sdk/dist/dc.base.min' | |||
| import DcCore from '@dvgis/dc-sdk/dist/dc.core.min' | |||
| import DcChart from '@dvgis/dc-sdk/dist/dc.chart.min' | |||
| import DcMapv from '@dvgis/dc-sdk/dist/dc.mapv.min' | |||
| import '@dvgis/dc-sdk/dist/dc.core.min.css' | |||
| ``` | |||
| `NPM / YARN` **_`(On-demand)`_** | |||
| ```shell | |||
| yarn add @dvgis/dc-base | |||
| yarn add @dvgis/dc-core | |||
| yarn add @dvgis/dc-chart | |||
| yarn add @dvgis/dc-mapv | |||
| ------------------------- | |||
| npm install @dvgis/dc-base | |||
| npm install @dvgis/dc-core | |||
| npm install @dvgis/dc-chart | |||
| npm install @dvgis/dc-mapv | |||
| ``` | |||
| ```js | |||
| import DC from '@dvgis/dc-base' | |||
| import DcCore from '@dvgis/dc-core' | |||
| import DcChart from '@dvgis/dc-chart' | |||
| import DcMapv from '@dvgis/dc-mapv' | |||
| import '@dvgis/dc-core/dist/dc.core.min.css' | |||
| ``` | |||
| `CDN` | |||
| [Resources](https://github.com/dvgis/dc-sdk/releases) | |||
| ```html | |||
| <script src="https://cdn.jsdelivr.net/npm/@dvgis/dc-sdk/dist/dc.base.min.js"></script> | |||
| <script src="https://cdn.jsdelivr.net/npm/@dvgis/dc-sdk/dist/dc.core.min.js"></script> | |||
| <script src="https://cdn.jsdelivr.net/npm/@dvgis/dc-sdk/dist/dc.chart.min.js"></script> | |||
| <script src="https://cdn.jsdelivr.net/npm/@dvgis/dc-sdk/dist/mapv.min.js"></script> | |||
| <link | |||
| href="https://cdn.jsdelivr.net/npm/@dvgis/dc-sdk/dist/dc.core.min.css" | |||
| rel="stylesheet" | |||
| type="text/css" | |||
| /> | |||
| ``` | |||
| ``` | |||
| Please put the resources in the project root directory libs/dc-sdk, if you put it in other directory, the framework will not run properly. | |||
| ``` | |||
| ## Configuration | |||
| > The configuration is mainly used in the `NPM / YARN` way | |||
| Since the `DC` framework sets `CESIUM_BASE_URL` to `./libs/dc-sdk/resources/` , you need to copy `Cesium` related static resources files: `Assets` , `Workers` , `ThirdParty `to `libs/dc-sdk/resources` directory of the project to ensure that the 3D scene can be rendered properly. You can also use `DC.baseUrl` to set the static resource base related to `Cesium` . | |||
| `Webpack` | |||
| [Project Template](https://github.com/cavencj/dc-vue-app) | |||
| ```js | |||
| // webpack.config.js | |||
| const path = require('path') | |||
| const CopywebpackPlugin = require('copy-webpack-plugin') | |||
| const dvgisDist = './node_modules/@dvgis' | |||
| module.exports = { | |||
| plugins: [ | |||
| new CopyWebpackPlugin([ | |||
| { | |||
| from: path.join(dvgisDist, 'dc-sdk/dist/resources'), | |||
| to: 'libs/dc-sdk/resources', | |||
| }, | |||
| ]), | |||
| ], | |||
| } | |||
| ``` | |||
| `Vue2.x` | |||
| [Project Template](https://github.com/dvgis/dc-vue) | |||
| ```js | |||
| // vue.config.js | |||
| const path = require('path') | |||
| const CopywebpackPlugin = require('copy-webpack-plugin') | |||
| const dvgisDist = './node_modules/@dvgis' | |||
| module.exports = { | |||
| chainWebpack: (config) => { | |||
| config.plugin('copy').use(CopywebpackPlugin, [ | |||
| [ | |||
| { | |||
| from: path.join(dvgisDist, 'dc-sdk/dist/resources'), | |||
| to: 'libs/dc-sdk/resources', | |||
| }, | |||
| ], | |||
| ]) | |||
| }, | |||
| } | |||
| ``` | |||
| `Vue3.x` | |||
| [Project Template](https://github.com/dvgis/dc-vue-next) | |||
| ```js | |||
| // vue.config.js | |||
| const path = require('path') | |||
| const CopywebpackPlugin = require('copy-webpack-plugin') | |||
| const dvgisDist = './node_modules/@dvgis' | |||
| module.exports = { | |||
| chainWebpack: (config) => { | |||
| config.plugin('copy').use(CopywebpackPlugin, [ | |||
| { | |||
| patterns: [ | |||
| { | |||
| from: path.join(dvgisDist, 'dc-sdk/dist/resources'), | |||
| to: path.join(__dirname, 'dist', 'libs/dc-sdk/resources'), | |||
| }, | |||
| ], | |||
| }, | |||
| ]) | |||
| }, | |||
| } | |||
| ``` | |||
| ## Start | |||
| ```js | |||
| global.DC = DC | |||
| DC.use(DcCore) // node | |||
| DC.ready(() => { | |||
| let viewer = new DC.Viewer(divId) // divId is the Id attribute value of a div node. If it is not passed in, the 3D scene cannot be initialized | |||
| }) | |||
| ``` | |||
| ## Demo | |||
| |  |  |  |  | | |||
| | :-----------------------------------------------------------: | :-----------------------------------------------------------: | :------------------------------------------------------------------: | :--------------------------------------------------------------: | | |||
| |  |  |  |  | | |||
| |  |  |  |  | | |||
| [More>>](http://dc.dvgis.cn/#/examples) | |||
| ## Ecosystem | |||
| | Module | Status | Description | | |||
| | :------ | :------: | :------ | | |||
| | [dc-chart](https://github.com/dvgis/dc-chart) | <img src="https://img.shields.io/npm/v/@dvgis/dc-chart?logo=npm" /> | dc chart module for adding ECharts functionality in 3d scenes | | |||
| | [dc-mapv](https://github.com/dvgis/dc-mapv) | <img src="https://img.shields.io/npm/v/@dvgis/dc-mapv?logo=npm" /> | dc big-data module for adding MAPV functions in 3d scenes | | |||
| | [dc-ui](https://github.com/dvgis/dc-ui) | <img src="https://img.shields.io/npm/v/@dvgis/dc-ui?logo=npm" /> | dc components for Vue2.x | | |||
| | dc-ui-next | <img src="https://img.shields.io/npm/v/@dvgis/dc-ui-next?logo=npm" /> | dc components for Vue3.x | | |||
| ## Copyright | |||
| ```warning | |||
| 1. The framework is a basic platform, completely open source, which can be modified and reconstructed by any individual or institution without our authorization. | |||
| 2. We are not responsible for any problems arising from the modification of the framework by individuals and organizations. | |||
| 3. Some industrial plug-ins and tools will be added in the later stage, and the code will be open source appropriately. | |||
| 4. The package released by us may be used permanently and free of charge by any person or organization subject to: | |||
| 1) complete package reference; | |||
| 2) reserve this copyright information in the console output | |||
| We reserve the right of final interpretation of this copyright information. | |||
| ``` | |||
| ## Support | |||
| > if dc-sdk can bring benefits to you, please support it ~ | |||
| <p> | |||
| <a href="https://www.paypal.com/paypalme/cavencj" target="_blank"> | |||
| <img src="https://www.paypalobjects.com/images/shared/paypal-logo-129x32.svg" style="margin-top:10px" /> | |||
| </a> | |||
| </p> | |||
| ## Thanks | |||
| @@ -0,0 +1,30 @@ | |||
| /** | |||
| * @Author: Caven | |||
| * @Date: 2021-03-12 16:45:45 | |||
| */ | |||
| const install = function(DC) { | |||
| if (!DC || !DC.init) { | |||
| throw new Error('Mapv: Missing DC Base') | |||
| } | |||
| DC.init(() => { | |||
| try { | |||
| DC.mixin(require('./src/components.js').default) | |||
| } catch (e) { | |||
| // eslint-disable-next-line no-console | |||
| console.error(e) | |||
| } | |||
| }) | |||
| } | |||
| /* istanbul ignore if */ | |||
| if (typeof window !== 'undefined' && window.DC) { | |||
| install(DC) | |||
| } | |||
| export default { | |||
| version: __VERSION__, | |||
| compile_time: __TIME__, | |||
| install | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| /** | |||
| * @Author: Caven | |||
| * @Date: 2021-03-13 17:17:19 | |||
| */ | |||
| import S3MLayer from '@dc-modules/mapv/MapvLayer' | |||
| const components = { S3MLayer } | |||
| export default components | |||