UNPKG

@itwin/core-frontend

Version:
333 lines (301 loc) • 12.7 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module WebGL */ Object.defineProperty(exports, "__esModule", { value: true }); exports.adjustWidth = void 0; exports.addAdjustWidth = addAdjustWidth; exports.addLineCodeTexture = addLineCodeTexture; exports.addLineCode = addLineCode; exports.createPolylineBuilder = createPolylineBuilder; exports.createPolylineHiliter = createPolylineHiliter; const core_bentley_1 = require("@itwin/core-bentley"); const AttributeMap_1 = require("../AttributeMap"); const RenderFlags_1 = require("../RenderFlags"); const ShaderBuilder_1 = require("../ShaderBuilder"); const System_1 = require("../System"); const Color_1 = require("./Color"); const Edge_1 = require("./Edge"); const Common_1 = require("./Common"); const Decode_1 = require("./Decode"); const FeatureSymbology_1 = require("./FeatureSymbology"); const Fragment_1 = require("./Fragment"); const Vertex_1 = require("./Vertex"); const Viewport_1 = require("./Viewport"); const checkForDiscard = "return discardByLineCode;"; const applyLineCode = ` if (v_texc.x >= 0.0) { // v_texc = (-1,-1) for solid lines - don't bother with any of this vec4 texColor = TEXTURE(u_lineCodeTexture, v_texc); discardByLineCode = (0.0 == texColor.r); } if (v_lnInfo.w > 0.5) { // line needs pixel trimming // calculate pixel distance from pixel center to expected line center, opposite dir from major vec2 dxy = gl_FragCoord.xy - v_lnInfo.xy; if (v_lnInfo.w < 1.5) // not x-major dxy = dxy.yx; float dist = v_lnInfo.z * dxy.x - dxy.y; float distA = abs(dist); if (distA > 0.5 || (distA == 0.5 && dist < 0.0)) discardByLineCode = true; // borrow this flag to force discard } return baseColor; `; const computeTextureCoord = ` vec2 computeLineCodeTextureCoords(vec2 windowDir, vec4 projPos, float adjust) { vec2 texc; float lineCode = computeLineCode(); if (0.0 == lineCode) { // Solid line - tell frag shader not to bother. texc = vec2(-1.0, -1.0); } else { const float imagesPerPixel = 1.0/32.0; const float textureCoordinateBase = 8192.0; // Temp workardound for clipping problem in perspective views (negative values don't seem to interpolate correctly). if (abs(windowDir.x) > abs(windowDir.y)) texc.x = textureCoordinateBase + imagesPerPixel * (projPos.x + adjust * windowDir.x); else texc.x = textureCoordinateBase + imagesPerPixel * (projPos.y + adjust * windowDir.y); const float numLineCodes = 16.0; // NB: Actually only 10, but texture is 16px tall because it needs to be a power of 2. const float rowsPerCode = 1.0; const float numRows = numLineCodes*rowsPerCode; const float centerY = 0.5/numRows; const float stepY = rowsPerCode/numRows; texc.y = stepY * lineCode + centerY; } return texc; } `; /** @internal */ exports.adjustWidth = ` void adjustWidth(inout float width, vec2 d2, vec2 org) { if (u_aaSamples > 1) { if (width < 5.0) width += (5.0 - width) * 0.125; return; } // calculate slope based width adjustment for non-AA lines, widths 1 to 4 vec2 d2A = abs(d2); const float s_myFltEpsilon = 0.0001; // limit test resolution to 4 digits in case 24 bit (s16e7) is used in hardware if (d2A.y > s_myFltEpsilon && width < 4.5) { float len = length(d2A); float tan = d2A.x / d2A.y; if (width < 1.5) { // width 1 if (tan <= 1.0) width = d2A.y; else width = d2A.x; // width 1 requires additional adjustment plus trimming in frag shader using v_lnInfo width *= 1.01; v_lnInfo.xy = org; v_lnInfo.w = 1.0; // set flag to do trimming // set slope in v_lnInfo.z if (d2A.x - d2A.y > s_myFltEpsilon) { v_lnInfo.z = d2.y / d2.x; v_lnInfo.w += 2.0; // add in x-major flag } else v_lnInfo.z = d2.x / d2.y; } else if (width < 2.5) { // width 2 if (tan <= 0.5) width = 2.0 * d2A.y; else width = (d2A.y + 2.0 * d2A.x); } else if (width < 3.5) { // width 3 if (tan <= 1.0) width = (3.0 * d2A.y + d2A.x); else width = (d2A.y + 3.0 * d2A.x); } else { // if (width < 4.5) // width 4 if (tan <= 0.5) width = (4.0 * d2A.y + d2A.x); else if (tan <= 2.0) width = (3.0 * d2A.y + 3.0 * d2A.x); else width = (d2A.y + 4.0 * d2A.x); } width /= len; } } `; /** @internal */ function addAdjustWidth(vert) { vert.addUniform("u_aaSamples", 1 /* VariableType.Int */, (prog) => { prog.addGraphicUniform("u_aaSamples", (attr, params) => { const numSamples = System_1.System.instance.frameBufferStack.currentFbMultisampled ? params.target.compositor.antialiasSamples : 1; attr.setUniform1i(numSamples); }); }); vert.addFunction(exports.adjustWidth); } /** @internal */ function addLineCodeTexture(frag) { frag.addUniform("u_lineCodeTexture", 8 /* VariableType.Sampler2D */, (prog) => { prog.addProgramUniform("u_lineCodeTexture", (uniform) => { const lct = System_1.System.instance.lineCodeTexture; (0, core_bentley_1.assert)(undefined !== lct); if (undefined !== lct) lct.bindSampler(uniform, RenderFlags_1.TextureUnit.LineCode); }); }); } /** @internal */ function addLineCode(prog, args) { const vert = prog.vert; const frag = prog.frag; (0, Vertex_1.addLineCode)(vert); const funcCall = `computeLineCodeTextureCoords(${args})`; prog.addFunctionComputedVaryingWithArgs("v_texc", 3 /* VariableType.Vec2 */, funcCall, computeTextureCoord); (0, Common_1.addFrustum)(prog); addLineCodeTexture(prog.frag); frag.set(3 /* FragmentShaderComponent.FinalizeBaseColor */, applyLineCode); frag.set(4 /* FragmentShaderComponent.CheckForDiscard */, checkForDiscard); frag.addGlobal("discardByLineCode", 0 /* VariableType.Boolean */, "false"); } function polylineAddLineCode(prog) { addLineCode(prog, lineCodeArgs); (0, Vertex_1.addModelViewMatrix)(prog.vert); } function addCommon(prog) { const vert = prog.vert; (0, Viewport_1.addModelToWindowCoordinates)(vert); // adds u_mvp, u_viewportTransformation (0, Vertex_1.addProjectionMatrix)(vert); (0, Vertex_1.addModelViewMatrix)(vert); (0, Viewport_1.addViewport)(vert); vert.addGlobal("g_windowPos", 5 /* VariableType.Vec4 */); vert.addGlobal("g_prevPos", 5 /* VariableType.Vec4 */); vert.addGlobal("g_nextPos", 5 /* VariableType.Vec4 */); vert.addGlobal("g_windowDir", 3 /* VariableType.Vec2 */); vert.addInitializer(decodeAdjacentPositions); vert.addFunction(Decode_1.unquantize2d); (0, Vertex_1.addLineWeight)(vert); vert.addGlobal("miterAdjust", 2 /* VariableType.Float */, "0.0"); prog.addVarying("v_eyeSpace", 4 /* VariableType.Vec3 */); vert.set(10 /* VertexShaderComponent.ComputePosition */, computePosition); prog.addVarying("v_lnInfo", 5 /* VariableType.Vec4 */); addAdjustWidth(vert); (0, Vertex_1.addSamplePosition)(vert); vert.addFunction(decodePosition); } const decodePosition = ` vec4 decodePosition(vec3 baseIndex) { float index = decodeUInt24(baseIndex); return samplePosition(index); } `; const decodeAdjacentPositions = ` g_prevPos = decodePosition(a_prevIndex); g_nextPos = decodePosition(a_nextIndex); `; const computePosition = ` const float kNone = 0.0, kSquare = 1.0*3.0, kMiter = 2.0*3.0, kMiterInsideOnly = 3.0*3.0, kJointBase = 4.0*3.0, kNegatePerp = 8.0*3.0, kNegateAlong = 16.0*3.0, kNoneAdjWt = 32.0*3.0; v_lnInfo = vec4(0.0, 0.0, 0.0, 0.0); // init and set flag to false vec4 next = g_nextPos; vec4 pos; g_windowPos = modelToWindowCoordinates(rawPos, next, pos, v_eyeSpace); if (g_windowPos.w == 0.0) return g_windowPos; float param = a_param; float weight = computeLineWeight(); float scale = 1.0, directionScale = 1.0; if (param >= kNoneAdjWt) param -= kNoneAdjWt; if (param >= kNegateAlong) { directionScale = -directionScale; param -= kNegateAlong; } if (param >= kNegatePerp) { scale = -1.0; param -= kNegatePerp; } vec4 otherPos; vec3 otherMvPos; vec4 projNext = modelToWindowCoordinates(next, rawPos, otherPos, otherMvPos); g_windowDir = projNext.xy - g_windowPos.xy; if (param < kJointBase) { vec2 dir = (directionScale > 0.0) ? g_windowDir : -g_windowDir; vec2 pos = (directionScale > 0.0) ? g_windowPos.xy : projNext.xy; adjustWidth(weight, dir, pos); } if (kNone != param) { vec2 delta = vec2(0.0); vec4 prev = g_prevPos; vec4 projPrev = modelToWindowCoordinates(prev, rawPos, otherPos, otherMvPos); vec2 prevDir = g_windowPos.xy - projPrev.xy; float thisLength = sqrt(g_windowDir.x * g_windowDir.x + g_windowDir.y * g_windowDir.y); const float s_minNormalizeLength = 1.0E-5; // avoid normalizing zero length vectors. float dist = weight / 2.0; if (thisLength > s_minNormalizeLength) { g_windowDir /= thisLength; float prevLength = sqrt(prevDir.x * prevDir.x + prevDir.y * prevDir.y); if (prevLength > s_minNormalizeLength) { prevDir /= prevLength; const float s_minParallelDot= -.9999, s_maxParallelDot = .9999; float prevNextDot = dot(prevDir, g_windowDir); if (prevNextDot < s_minParallelDot || prevNextDot > s_maxParallelDot) // No miter if parallel or antiparallel. param = kSquare; } else param = kSquare; } else { g_windowDir = -normalize(prevDir); param = kSquare; } vec2 perp = scale * vec2(-g_windowDir.y, g_windowDir.x); if (param == kSquare) { delta = perp; } else { vec2 bisector = normalize(prevDir - g_windowDir); float dotP = dot (bisector, perp); if (dotP != 0.0) { // Should never occur - but avoid divide by zero. const float maxMiter = 3.0; float miterDistance = 1.0/dotP; if (param == kMiter) { // Straight miter. delta = (abs(miterDistance) > maxMiter) ? perp : bisector * miterDistance; } else if (param == kMiterInsideOnly) { // Miter at inside, square at outside (to make room for joint). delta = (dotP > 0.0 || abs(miterDistance) > maxMiter) ? perp : bisector * miterDistance; } else { const float jointTriangleCount = 3.0; float ratio = (param - kJointBase) / jointTriangleCount; // 3 triangles per half-joint as defined in Graphics.cpp delta = normalize((1.0 - ratio) * bisector + (dotP < 0.0 ? -ratio : ratio) * perp); // Miter/Straight combination. } } } miterAdjust = dot(g_windowDir, delta) * dist; // Not actually used for hilite shader but meh. pos.x += dist * delta.x * 2.0 * pos.w / u_viewport.x; pos.y += dist * delta.y * 2.0 * pos.w / u_viewport.y; } return pos; `; const lineCodeArgs = "g_windowDir, g_windowPos, miterAdjust"; /** @internal */ function createPolylineBuilder(isInstanced, positionType) { const instanced = 1 /* IsInstanced.Yes */ === isInstanced; const attrMap = AttributeMap_1.AttributeMap.findAttributeMap(1 /* TechniqueId.Polyline */, instanced); const builder = new ShaderBuilder_1.ProgramBuilder(attrMap, { positionType, instanced }); (0, Common_1.addShaderFlags)(builder); addCommon(builder); polylineAddLineCode(builder); (0, Color_1.addColor)(builder); (0, Edge_1.addEdgeContrast)(builder.vert); (0, Fragment_1.addWhiteOnWhiteReversal)(builder.frag); return builder; } /** @internal */ function createPolylineHiliter(isInstanced, positionType) { const instanced = 1 /* IsInstanced.Yes */ === isInstanced; const attrMap = AttributeMap_1.AttributeMap.findAttributeMap(1 /* TechniqueId.Polyline */, instanced); const builder = new ShaderBuilder_1.ProgramBuilder(attrMap, { positionType, instanced }); addCommon(builder); (0, Common_1.addFrustum)(builder); (0, FeatureSymbology_1.addHiliter)(builder, true); return builder; } //# sourceMappingURL=Polyline.js.map