diff --git a/src/mol-gl/shader-code.ts b/src/mol-gl/shader-code.ts index 63836245aa67f1a6ee4e2847932119782561af63..5e7c1047554902e85a29353764a7fcbf4bf2efad 100644 --- a/src/mol-gl/shader-code.ts +++ b/src/mol-gl/shader-code.ts @@ -101,7 +101,8 @@ const ShaderChunks: { [k: string]: string } = { wboit_write }; -const reInclude = /^(?!\/\/)\s*#include\s+(\S+)/gmi; +const reInclude = /^(?!\/\/)\s*#include\s+(\S+)/gm; +const reUnrollLoop = /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*\+\+i\s*\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g; const reSingleLineComment = /[ \t]*\/\/.*\n/g; const reMultiLineComment = /[ \t]*\/\*[\s\S]*?\*\//g; const reMultipleLinebreaks = /\n{2,}/g; @@ -119,6 +120,29 @@ function addIncludes(text: string) { .replace(reMultipleLinebreaks, '\n'); } +function unrollLoops(str: string) { + return str.replace(reUnrollLoop, loopReplacer); +} + +function loopReplacer(match: string, start: string, end: string, snippet: string) { + let out = ''; + for (let i = parseInt(start); i < parseInt(end); ++i) { + out += snippet + .replace(/\[\s*i\s*\]/g, `[${i}]`) + .replace(/UNROLLED_LOOP_INDEX/g, `${i}`); + } + return out; +} + +function replaceCounts(str: string, defines: ShaderDefines) { + if (defines.dClipObjectCount) str = str.replace(/dClipObjectCount/g, `${defines.dClipObjectCount.ref.value}`); + return str; +} + +function preprocess(str: string, defines: ShaderDefines) { + return unrollLoops(replaceCounts(str, defines)); +} + export function ShaderCode(name: string, vert: string, frag: string, extensions: ShaderExtensions = {}, outTypes: FragOutTypes = {}): ShaderCode { return { id: shaderCodeId(), name, vert: addIncludes(vert), frag: addIncludes(frag), extensions, outTypes }; } @@ -278,8 +302,8 @@ export function addShaderDefines(gl: GLRenderingContext, extensions: WebGLExtens return { id: shaderCodeId(), name: shaders.name, - vert: `${vertPrefix}${header}${shaders.vert}`, - frag: `${fragPrefix}${header}${frag}`, + vert: `${vertPrefix}${header}${preprocess(shaders.vert, defines)}`, + frag: `${fragPrefix}${header}${preprocess(frag, defines)}`, extensions: shaders.extensions, outTypes: shaders.outTypes }; diff --git a/src/mol-gl/shader/chunks/common-clip.glsl.ts b/src/mol-gl/shader/chunks/common-clip.glsl.ts index f38c78a1eb11a34e62e2a7bebcac034693245679..5bca9dec16e2dd3069af86b7316f00813fda279e 100644 --- a/src/mol-gl/shader/chunks/common-clip.glsl.ts +++ b/src/mol-gl/shader/chunks/common-clip.glsl.ts @@ -89,8 +89,9 @@ export const common_clip = ` // flag is a bit-flag for clip-objects to ignore (note, object ids start at 1 not 0) bool clipTest(vec4 sphere, int flag) { + #pragma unroll_loop_start for (int i = 0; i < dClipObjectCount; ++i) { - if (flag == 0 || hasBit(flag, i + 1)) { + if (flag == 0 || hasBit(flag, UNROLLED_LOOP_INDEX + 1)) { // TODO take sphere radius into account? bool test = getSignedDistance(sphere.xyz, uClipObjectType[i], uClipObjectPosition[i], uClipObjectRotation[i], uClipObjectScale[i]) <= 0.0; if ((!uClipObjectInvert[i] && test) || (uClipObjectInvert[i] && !test)) { @@ -98,6 +99,7 @@ export const common_clip = ` } } } + #pragma unroll_loop_end return false; } #endif