UNPKG

@awayjs/renderer

Version:
573 lines (572 loc) 26.6 kB
import { __extends } from "tslib"; import { Box, Vector3D } from '@awayjs/core'; import { AttributesView, Byte4Attributes, Float1Attributes } from '@awayjs/stage'; import { ElementsBase } from './ElementsBase'; var TMP_BBOX = new Box(); /** * @class LineElements */ var LineElements = /** @class */ (function (_super) { __extends(LineElements, _super); /** * */ function LineElements(concatenatedBuffer) { if (concatenatedBuffer === void 0) { concatenatedBuffer = null; } var _this = _super.call(this, concatenatedBuffer) || this; _this._thicknessScale = new Vector3D(); //used for hittesting geometry _this.hitTestCache = new Object(); _this.half_thickness = 5; _this.scaleMode = LineScaleMode.HAIRLINE; _this.dimension = 3; _this.dimension = Settings.LINE_BUFFER_DIM; _this._positions = new AttributesView(Float32Array, _this.dimension * 2, concatenatedBuffer); return _this; } LineElements.prototype.getThicknessScale = function (node, strokeFlag) { if (!strokeFlag && this.scaleMode == LineScaleMode.HAIRLINE) { this._thicknessScale.identity(); } else { if (node) this._thicknessScale.copyFrom(node.getMatrix3D().decompose()[3]); else this._thicknessScale.identity(); this._thicknessScale.x *= node.view.focalLength * node.view.pixelRatio / 1000; this._thicknessScale.y *= node.view.focalLength / 1000; if (this.scaleMode == LineScaleMode.NORMAL) { this._thicknessScale.x = (!strokeFlag || this.half_thickness * this._thicknessScale.x > 0.5) ? this.half_thickness : this._thicknessScale.x ? 0.5 / this._thicknessScale.x : 0; this._thicknessScale.y = (!strokeFlag || this.half_thickness * this._thicknessScale.y > 0.5) ? this.half_thickness : this._thicknessScale.y ? 0.5 / this._thicknessScale.y : 0; } else if (this.scaleMode == LineScaleMode.HAIRLINE) { this._thicknessScale.x = this._thicknessScale.x ? 0.5 / this._thicknessScale.x : 0; this._thicknessScale.y = this._thicknessScale.y ? 0.5 / this._thicknessScale.y : 0; } } return this._thicknessScale; }; Object.defineProperty(LineElements.prototype, "assetType", { /** * * @returns {string} */ get: function () { return LineElements.assetType; }, enumerable: false, configurable: true }); Object.defineProperty(LineElements.prototype, "positions", { /** * */ get: function () { return this._positions; }, enumerable: false, configurable: true }); Object.defineProperty(LineElements.prototype, "thickness", { /** * */ get: function () { return this._thickness; }, enumerable: false, configurable: true }); Object.defineProperty(LineElements.prototype, "colors", { /** * */ get: function () { if (!this._colors) this.setColors(this._colors); return this._colors; }, enumerable: false, configurable: true }); LineElements.prototype.prepareScale9 = function (bounds, grid, clone, _emitUV, _uvMatrix) { return LineElementsUtils.prepareScale9(this, bounds, grid, clone); }; LineElements.prototype.updateScale9 = function (scaleX, scaleY) { if (!this.scale9Indices) { return; } LineElementsUtils.updateScale9(this, this.originalScale9Bounds, scaleX, scaleY, false, false); }; LineElements.prototype.getBoxBounds = function (node, strokeFlag, matrix3D, cache, target, count, offset) { if (node === void 0) { node = null; } if (strokeFlag === void 0) { strokeFlag = false; } if (matrix3D === void 0) { matrix3D = null; } if (cache === void 0) { cache = null; } if (target === void 0) { target = null; } if (count === void 0) { count = 0; } if (offset === void 0) { offset = 0; } count = count || this._numElements || this._numVertices; this._boundsRequests++; if (Settings.ENABLE_CONVEX_BOUNDS && this._boundsRequests > Settings.CONVEX_MIN_REQUIEST_FOR_BUILD && count > Settings.POINTS_COUNT_FOR_CONVEX && !this.isDynamic // diable for dynamic elements, beacause a reconstructed every frame ) { if (!this._convexHull || this._convexHull.count !== count // drop hull data, invalid || this._convexHull.offset !== offset // drop hull data, invalid ) { this._convexHull = ConvexHullUtils.fromAttribute(this.positions, this.indices, 3, // line elements has to many attirbutes, tick every 3 count, offset); if (this._convexHull) { this._convexHull.offset = offset; this._convexHull.count = count; console.debug('[Line] Build convex for:', this.id, 'vertex / hull', (count / this._convexHull.points.length) | 0); } } if (this._convexHull) { var tmp = TMP_BBOX; tmp.identity(); var box = ConvexHullUtils.createBox(this._convexHull, matrix3D, null, tmp); LineElementsUtils.mergeThinkness(box, this.getThicknessScale(node, strokeFlag), matrix3D); return tmp.union(target, target || cache); } } return LineElementsUtils.getBoxBounds(this.positions, this.indices, matrix3D, this.getThicknessScale(node, strokeFlag), cache, target, count, offset); }; LineElements.prototype.getSphereBounds = function (center, matrix3D, strokeFlag, cache, target, count, offset) { if (matrix3D === void 0) { matrix3D = null; } if (strokeFlag === void 0) { strokeFlag = false; } if (cache === void 0) { cache = null; } if (target === void 0) { target = null; } if (count === void 0) { count = 0; } if (offset === void 0) { offset = 0; } return LineElementsUtils.getSphereBounds(this.positions, center, matrix3D, cache, target, count || this._numVertices, offset); }; LineElements.prototype.hitTestPoint = function (node, x, y, z, box, count, offset, idx_count, idx_offset) { if (count === void 0) { count = 0; } if (offset === void 0) { offset = 0; } if (idx_count === void 0) { idx_count = 0; } if (idx_offset === void 0) { idx_offset = 0; } var scale = this.getThicknessScale(node, true); var thickness = (scale.x + scale.y) / 2; //approx hack for now return LineElementsUtils.hitTest(x, y, 0, thickness, box, this, count || this._numElements || this._numVertices, offset); }; LineElements.prototype.setPositions = function (values, offset) { if (offset === void 0) { offset = 0; } var dimension = this.dimension * 2; if (values instanceof AttributesView) { this.clearVertices(this._positions); this._positions = values; } else if (values) { var i = 0; var j = 0; var index = 0; var positions = new Float32Array(dimension * 4 * (values.length / 6)); var indices = new Uint16Array(values.length); //oders incoming startpos/endpos values to look like the following 6-dimensional attributes view: //startpos x, y, z endpos x, y, z //endpos x, y, z startpos x, y, z //startpos x, y, z endpos x, y, z //endpos x, y, z startpos x, y, z while (i < values.length) { if (index / dimension & 1) { //if number is odd, reverse the order of startpos/endpos positions[index++] = values[i + 3]; positions[index++] = values[i + 4]; dimension === 6 && (positions[index++] = values[i + 5]); positions[index++] = values[i]; positions[index++] = values[i + 1]; dimension === 6 && (positions[index++] = values[i + 2]); } else { positions[index++] = values[i]; positions[index++] = values[i + 1]; dimension === 6 && (positions[index++] = values[i + 2]); positions[index++] = values[i + 3]; positions[index++] = values[i + 4]; dimension === 6 && (positions[index++] = values[i + 5]); } //index += 6; if (++j == 4) { var o = index / dimension - 4; indices.set([o, o + 1, o + 2, o + 3, o + 2, o + 1], i); j = 0; i += 6; } } this._positions.set(positions, offset * 4); this.setIndices(indices, offset); } else { this.clearVertices(this._positions); this._positions = new AttributesView(Float32Array, dimension, this._concatenatedBuffer); } this._numVertices = this._positions.count; this.invalidateVertices(this._positions); this._verticesDirty[this._positions.id] = false; }; LineElements.prototype.setThickness = function (values, offset) { if (offset === void 0) { offset = 0; } if (values instanceof Float1Attributes) { this._thickness = values; } else if (values) { if (!this._thickness) this._thickness = new Float1Attributes(this._concatenatedBuffer); var i = 0; var j = 0; var index = 0; var thickness = new Float32Array(values.length * 4); //oders incoming thickness values to look like the following 1-dimensional attributes view: //thickness t //thickness -t //thickness -t //thickness t while (i < values.length) { thickness[index] = (Math.floor(0.5 * index + 0.5) & 1) ? -values[i] : values[i]; if (++j == 4) { j = 0; i++; } index++; } this._thickness.set(thickness, offset * 4); } else if (this._thickness) { this._thickness.dispose(); this._thickness = null; } this.invalidateVertices(this._thickness); this._verticesDirty[this._thickness.id] = false; }; LineElements.prototype.setColors = function (values, offset) { if (offset === void 0) { offset = 0; } if (values) { if (values == this._colors) return; if (values instanceof Byte4Attributes) { this.clearVertices(this._colors); this._colors = values; } else { if (!this._colors) this._colors = new Byte4Attributes(this._concatenatedBuffer); var i = 0; var j = 0; var index = 0; var colors = new Uint8Array(values.length * 4); while (i < values.length) { if (index / 4 & 1) { colors[index] = values[i + 4]; colors[index + 1] = values[i + 5]; colors[index + 2] = values[i + 6]; colors[index + 3] = values[i + 7]; } else { colors[index] = values[i]; colors[index + 1] = values[i + 1]; colors[index + 2] = values[i + 2]; colors[index + 3] = values[i + 3]; } if (++j == 4) { j = 0; i += 8; } index += 4; } this._colors.set(colors, offset * 4); } } else { //auto-derive colors this._colors = ElementsUtils.generateColors(this.indices, this._colors, this._concatenatedBuffer, this._numVertices); } this.invalidateVertices(this._colors); this._verticesDirty[this._colors.id] = false; }; /** * */ LineElements.prototype.dispose = function () { _super.prototype.dispose.call(this); this._positions.dispose(); this._positions = null; if (this._thickness) { this._thickness.dispose(); this._thickness = null; } if (this._colors) { this._colors.dispose(); this._colors = null; } }; /** * Clones the current object * @return An exact duplicate of the current object. */ LineElements.prototype.clone = function () { var clone = new LineElements(this._concatenatedBuffer ? this._concatenatedBuffer.clone() : null); clone.setIndices(this.indices.clone()); clone.setPositions(this._positions.clone()); this._thickness && clone.setThickness(this._thickness.clone()); this._colors && clone.setColors(this._colors.clone()); return clone; }; LineElements.prototype.testCollision = function (collision, box, closestFlag, material, count, offset) { if (offset === void 0) { offset = 0; } //TODO: peform correct line collision calculations var scale = this.getThicknessScale(collision.containerNode, true); var thickness = (scale.x + scale.y) / 2; //approx hack for now var rayEntryDistance = -collision.rayPosition.z / collision.rayDirection.z; var position = new Vector3D(collision.rayPosition.x + rayEntryDistance * collision.rayDirection.x, collision.rayPosition.y + rayEntryDistance * collision.rayDirection.y); //TODO use proper 3d testCollision method if (LineElementsUtils.hitTest(position.x, position.y, 0, thickness, box, this, this._numElements, offset)) { collision.rayEntryDistance = rayEntryDistance; collision.position = position; collision.normal = new Vector3D(0, 0, 1); return true; } return false; }; LineElements.assetType = '[asset LineElements]'; return LineElements; }(ElementsBase)); export { LineElements }; import { Matrix3D } from '@awayjs/core'; import { ContextGLDrawMode, ContextGLProgramType, Stage } from '@awayjs/stage'; import { ElementsUtils } from '../utils/ElementsUtils'; import { _Stage_ElementsBase } from '../base/_Stage_ElementsBase'; import { _Render_ElementsBase } from '../base/_Render_ElementsBase'; import { RenderGroup } from '../RenderGroup'; import { LineElementsUtils } from '../utils/LineElementsUtils'; import { ConvexHullUtils } from '../utils/ConvexHullUtils'; import { Settings } from '../Settings'; import { LineScaleMode } from './LineScaleMode'; /** * * @class away.pool._Stage_LineElements */ var _Stage_LineElements = /** @class */ (function (_super) { __extends(_Stage_LineElements, _super); function _Stage_LineElements() { var _this = _super !== null && _super.apply(this, arguments) || this; _this._scale = new Vector3D(); _this._thickness = 1; _this._vaoIsInvalid = true; return _this; } _Stage_LineElements.prototype.init = function (lineElements, stage) { _super.prototype.init.call(this, lineElements, stage); this._lineElements = lineElements; this._vao = (stage.context.hasVao && Settings.ALLOW_VAO && !this._lineElements.isDynamic) ? stage.context.createVao() : null; }; _Stage_LineElements.prototype.onInvalidate = function (event) { _super.prototype.onInvalidate.call(this, event); this._vaoIsInvalid = true; }; _Stage_LineElements.prototype.onClear = function (event) { _super.prototype.onClear.call(this, event); this._lineElements = null; this._vaoIsInvalid = true; if (this._vao) { this._vao.dispose(); this._vao = null; } }; _Stage_LineElements.prototype._setRenderState = function (renderRenderable, shader) { _super.prototype._setRenderState.call(this, renderRenderable, shader); var asset = this._asset; var view = shader.view; var renderElements = renderRenderable.entity .renderer.getRenderElements(renderRenderable.stageElements.elements); this._vao && this._vao.bind(); if (!this._vao || this._vaoIsInvalid) { if (shader.colorBufferIndex >= 0) this.activateVertexBufferVO(shader.colorBufferIndex, this._lineElements.colors); this.activateVertexBufferVO(0, this._lineElements.positions, asset.dimension); this.activateVertexBufferVO(renderElements.secondaryPositionIndex, this._lineElements.positions, asset.dimension, asset.dimension * 2 * 2); this.activateVertexBufferVO(renderElements.thicknessIndex, this._lineElements.thickness); if (shader.uvIndex >= 0) { this.activateVertexBufferVO(shader.uvIndex, this._lineElements.positions, 2); } this._vaoIsInvalid = false; } var oMisc = renderElements.uOffsets.oMisc; var data = shader.vertexConstantData; this._scale.copyFrom(renderRenderable.entity.node.getMatrix3D().decompose()[3]); var scaleMode = this._lineElements.scaleMode; var half_thickness = this._lineElements.half_thickness; if (scaleMode == LineScaleMode.NORMAL) { data[oMisc + 0] = ( // eslint-disable-next-line max-len (half_thickness * this._scale.x * this._thickness / 1000 > 0.5 / (view.focalLength * view.pixelRatio)) ? this._scale.x * this._thickness / 1000 : 0.5 / (half_thickness * view.focalLength * view.pixelRatio)); data[oMisc + 1] = (half_thickness * this._scale.y * this._thickness / 1000 > 0.5 / view.focalLength) ? this._scale.y * this._thickness / 1000 : 0.5 / (half_thickness * view.focalLength); } else if (scaleMode == LineScaleMode.HAIRLINE) { data[oMisc + 0] = this._thickness / (view.focalLength * view.pixelRatio); data[oMisc + 1] = this._thickness / view.focalLength; } else { data[oMisc + 0] = this._thickness / Math.min(view.width, view.height); data[oMisc + 1] = this._thickness / Math.min(view.width, view.height); } data[oMisc + 2] = view.projection.near; }; _Stage_LineElements.prototype.draw = function (renderRenderable, shader, count, offset) { var context = this._stage.context; // projection matrix shader.viewMatrix.copyFrom(shader.view.frustumMatrix3D, true); var matrix3D = Matrix3D.CALCULATION_MATRIX; matrix3D.copyFrom(renderRenderable.entity.node.getMatrix3D()); matrix3D.append(shader.view.projection.transform.inverseMatrix3D); shader.sceneMatrix.copyFrom(matrix3D, true); context.setProgramConstantsFromArray(ContextGLProgramType.VERTEX, shader.vertexConstantData); context.setProgramConstantsFromArray(ContextGLProgramType.FRAGMENT, shader.fragmentConstantData); if (this._indices) this.getIndexBufferGL().draw(ContextGLDrawMode.TRIANGLES, offset * 3, count * 3 || this.numIndices); else this._stage.context.drawVertices(ContextGLDrawMode.TRIANGLES, offset, count || this.numVertices); this._vao && this._vao.unbind(); }; /** * //TODO * * @param pool * @param renderRenderable * @param level * @param indexOffset * @returns {away.pool.LineSubSpriteRenderable} * @protected */ _Stage_LineElements.prototype._pGetOverflowElements = function () { return this._lineElements.getNewAbstraction(this._stage); }; return _Stage_LineElements; }(_Stage_ElementsBase)); export { _Stage_LineElements }; /** * @class away.pool._Render_LineElements */ var _Render_LineElements = /** @class */ (function (_super) { __extends(_Render_LineElements, _super); function _Render_LineElements() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.secondaryPositionIndex = -1; _this.thicknessIndex = -1; _this.uOffsets = { oMisc: 0, }; return _this; } _Render_LineElements.prototype._includeDependencies = function (shader) { //shader.colorDependencies++; }; _Render_LineElements.prototype._getVertexCode = function (shader, registerCache, sharedRegisters) { //get the projection coordinates var position0 = (shader.globalPosDependencies > 0) ? sharedRegisters.globalPositionVertex : sharedRegisters.animatedPosition; var position1 = registerCache.getFreeVertexAttribute(); this.secondaryPositionIndex = position1.index; var thickness = registerCache.getFreeVertexAttribute(); this.thicknessIndex = thickness.index; //reserving vertex constants for projection matrix var viewMatrixReg = registerCache.getFreeVertexConstant(); registerCache.getFreeVertexConstant(); registerCache.getFreeVertexConstant(); registerCache.getFreeVertexConstant(); shader.viewMatrixIndex = viewMatrixReg.index * 4; var misc = registerCache.getFreeVertexConstant(); this.uOffsets.oMisc = misc.index * 4; var sceneMatrixReg = registerCache.getFreeVertexConstant(); registerCache.getFreeVertexConstant(); registerCache.getFreeVertexConstant(); registerCache.getFreeVertexConstant(); shader.sceneMatrixIndex = sceneMatrixReg.index * 4; var q0 = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(q0, 1); var q1 = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(q1, 1); var l = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(l, 1); var behind = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(behind, 1); var qclipped = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(qclipped, 1); var offset = registerCache.getFreeVertexVectorTemp(); registerCache.addVertexTempUsages(offset, 1); // transform Q0 to eye space var code = [ 'm44 ' + q0 + ', ' + position0 + ', ' + sceneMatrixReg, 'm44 ' + q1 + ', ' + position1 + ', ' + sceneMatrixReg, 'sub ' + l + ', ' + q1 + ', ' + q0 + ' ', // test if behind camera near plane // if 0 - Q0.z < Camera.near then the point needs to be clipped 'slt ' + behind + '.x, ' + q0 + '.z, ' + misc + '.z', 'sub ' + behind + '.y, #native( 1.0 )native#, ' + behind + '.x ', // p = point on the plane (0,0,-near) // n = plane normal (0,0,-1) // D = Q1 - Q0 // t = ( dot( n, ( p - Q0 ) ) / ( dot( n, d ) // solve for t where line crosses Camera.near 'add ' + offset + '.x, ' + q0 + '.z, ' + misc + '.z ', 'sub ' + offset + '.y, ' + q0 + '.z, ' + q1 + '.z ', // fix divide by zero for horizontal lines 'seq ' + offset + '.z, ' + offset + '.y, #native( vec4(0.0) )native#', 'add ' + offset + '.y, ' + offset + '.y, ' + offset + '.z', 'div ' + offset + '.z, ' + offset + '.x, ' + offset + '.y', 'mul ' + offset + '.xyz, ' + offset + '.zzz, ' + l + '.xyz ', 'add ' + qclipped + '.xyz, ' + q0 + '.xyz, ' + offset + '.xyz ', 'mov ' + qclipped + '.w, #native( 1.0 )native# ', // If necessary, replace Q0 with new Qclipped 'mul ' + q0 + ', ' + q0 + ', ' + behind + '.yyyy ', 'mul ' + qclipped + ', ' + qclipped + ', ' + behind + '.xxxx ', 'add ' + q0 + ', ' + q0 + ', ' + qclipped + ' ', // calculate side vector for line 'nrm ' + l + '.xyz, ' + l + '.xyz ', 'nrm ' + behind + '.xyz, ' + q0 + '.xyz ', 'mov ' + behind + '.w, #native( 1.0 )native# ', 'crs ' + qclipped + '.xyz, ' + l + ', ' + behind + ' ', 'nrm ' + qclipped + '.xyz, ' + qclipped + '.xyz ', // face the side vector properly for the given point 'mul ' + qclipped + '.xyz, ' + qclipped + '.xyz, ' + thickness + '.xxx ', 'mov ' + qclipped + '.w, #native( 1.0 )native# ', // calculate the amount required to move at the point's distance to correspond to the line's pixel width // scale the side vector by that amount 'mul ' + offset + '.x, ' + q0 + '.z, #native( -1.0 )native# ', 'mul ' + qclipped + '.xyz, ' + qclipped + '.xyz, ' + offset + '.xxx ', 'mul ' + qclipped + '.xyz, ' + qclipped + '.xyz, ' + misc + '.xy ', // add scaled side vector to Q0 and transform to clip space 'add ' + q0 + '.xyz, ' + q0 + '.xyz, ' + qclipped + '.xyz ', // transform Q0 to clip space 'm44 op, ' + q0 + ', ' + viewMatrixReg, '' ]; registerCache.removeVertexTempUsage(q0); registerCache.removeVertexTempUsage(q1); registerCache.removeVertexTempUsage(l); registerCache.removeVertexTempUsage(behind); registerCache.removeVertexTempUsage(qclipped); registerCache.removeVertexTempUsage(offset); return code.join('\n'); }; _Render_LineElements.prototype._getFragmentCode = function (shader, registerCache, sharedRegisters) { return ''; }; return _Render_LineElements; }(_Render_ElementsBase)); export { _Render_LineElements }; RenderGroup.registerElements(_Render_LineElements, LineElements); Stage.registerAbstraction(_Stage_LineElements, LineElements);