diff --git a/apps/typegpu-docs/src/examples/geometry/circles/index.ts b/apps/typegpu-docs/src/examples/geometry/circles/index.ts index 4061b2fff..c39a0c96f 100644 --- a/apps/typegpu-docs/src/examples/geometry/circles/index.ts +++ b/apps/typegpu-docs/src/examples/geometry/circles/index.ts @@ -17,7 +17,7 @@ if (!context) { } const adapter = await navigator.gpu.requestAdapter(); -console.log(`Using ${adapter?.info.vendor} adapter`); +// console.log(`Using ${adapter?.info.vendor} adapter`); const device = await adapter?.requestDevice({ requiredFeatures: ['timestamp-query'], }); @@ -137,7 +137,7 @@ const pipeline = root['~unstable'] setTimeout(() => { pipeline - .with(bindGroupLayout, uniformsBindGroup) + .with(uniformsBindGroup) .withColorAttachment({ ...(multisample ? { @@ -157,6 +157,8 @@ setTimeout(() => { .draw(circleVertexCount(4), circleCount); }, 100); +// #region Example controls & Cleanup export function onCleanup() { root.destroy(); } +// #endregion diff --git a/apps/typegpu-docs/src/examples/geometry/lines-combinations/index.ts b/apps/typegpu-docs/src/examples/geometry/lines-combinations/index.ts index 4425ae804..ad7637e44 100644 --- a/apps/typegpu-docs/src/examples/geometry/lines-combinations/index.ts +++ b/apps/typegpu-docs/src/examples/geometry/lines-combinations/index.ts @@ -32,7 +32,7 @@ import { import { clamp, cos, min, mix, select, sin } from 'typegpu/std'; import type { ColorAttachment } from '../../../../../../packages/typegpu/src/core/pipeline/renderPipeline.ts'; import { TEST_SEGMENT_COUNT } from './constants.ts'; -import * as testCases from './testCases.ts'; +import { testCases } from './testCases.ts'; const presentationFormat = navigator.gpu.getPreferredCanvasFormat(); const canvas = document.querySelector('canvas'); @@ -146,7 +146,7 @@ const mainVertex = tgpu['~unstable'].vertexFn({ }; }); -console.log(tgpu.resolve({ externals: { lineSegmentVariableWidth } })); +// console.log(tgpu.resolve([lineSegmentVariableWidth])); const mainFragment = tgpu['~unstable'].fragmentFn({ in: { @@ -192,13 +192,13 @@ const mainFragment = tgpu['~unstable'].fragmentFn({ vec3f(0.25, 0.25, 0.75), // 8 ]; if (fillType === 2) { - color = colors[instanceIndex % colors.length]; + color = vec3f(colors[instanceIndex % colors.length]); } if (fillType === 3) { - color = colors[vertexIndex % colors.length]; + color = vec3f(colors[vertexIndex % colors.length]); } if (fillType === 4) { - color = colors[situationIndex % colors.length]; + color = vec3f(colors[situationIndex % colors.length]); } if (fillType === 5) { color = vec3f(uv.x, cos(uv.y * 100), 0); @@ -304,11 +304,16 @@ function createPipelines() { format: presentationFormat, blend: alphaBlend, }) - .withPrimitive({ - // cullMode: 'back', - }) + // .withPrimitive({ + // cullMode: 'back', + // }) .createPipeline() - .withIndexBuffer(indexBuffer); + .withIndexBuffer(indexBuffer) + .withPerformanceCallback((start, end) => { + if (frameId % 20 === 0) { + console.log(`${(Number(end - start) * 1e-6).toFixed(2)} ms`); + } + }); const outline = root['~unstable'] .with(joinSlot, join) @@ -383,11 +388,6 @@ const draw = (timeMs: number) => { pipelines.fill .with(uniformsBindGroup) .withColorAttachment({ ...colorAttachment, loadOp: 'clear' }) - .withPerformanceCallback((start, end) => { - if (frameId % 20 === 0) { - console.log(`${(Number(end - start) * 1e-6).toFixed(2)} ms`); - } - }) .drawIndexed(subdiv.fillCount, fillType === 0 ? 0 : TEST_SEGMENT_COUNT); if (wireframe) { @@ -449,12 +449,12 @@ const subdivs = [ }, ]; +// #region Example controls & Cleanup export const controls = { 'Test Case': { initial: Object.keys(testCases)[0], options: Object.keys(testCases), - onSelectChange: async (selected: keyof typeof testCases) => { - // biome-ignore lint/performance/noDynamicNamespaceImportAccess: no other way + onSelectChange: (selected: keyof typeof testCases) => { testCase = testCases[selected]; pipelines = createPipelines(); }, @@ -462,7 +462,7 @@ export const controls = { 'Start Cap': { initial: 'round', options: Object.keys(lineCaps), - onSelectChange: async (selected: keyof typeof lineCaps) => { + onSelectChange: (selected: keyof typeof lineCaps) => { startCap = lineCaps[selected]; pipelines = createPipelines(); }, @@ -470,7 +470,7 @@ export const controls = { 'End Cap': { initial: 'round', options: Object.keys(lineCaps), - onSelectChange: async (selected: keyof typeof lineCaps) => { + onSelectChange: (selected: keyof typeof lineCaps) => { endCap = lineCaps[selected]; pipelines = createPipelines(); }, @@ -478,7 +478,7 @@ export const controls = { Join: { initial: 'round', options: Object.keys(lineJoins), - onSelectChange: async (selected: keyof typeof lineJoins) => { + onSelectChange: (selected: keyof typeof lineJoins) => { join = lineJoins[selected]; pipelines = createPipelines(); }, @@ -486,7 +486,7 @@ export const controls = { Fill: { initial: 'solid', options: Object.keys(fillOptions), - onSelectChange: async (selected: keyof typeof fillOptions) => { + onSelectChange: (selected: keyof typeof fillOptions) => { fillType = fillOptions[selected]; uniformsBuffer.writePartial({ fillType }); }, @@ -527,9 +527,56 @@ export const controls = { reverse = value; }, }, + 'Test Resolution': import.meta.env.DEV && { + onButtonClick: () => { + const prevShowRadii = showRadii; + const prevStartCap = startCap; + const prevEndCap = endCap; + const prevJoin = join; + const prevTestCase = testCase; + + showRadii = true; + + const capsOptions = Object.keys(lineCaps); + const joinOptions = Object.keys(lineJoins); + + const { animateWidth, bending, segmentAlternate } = testCases; + const testCasesReduced = { animateWidth, bending, segmentAlternate }; // semi-random subset + + Object.entries(testCasesReduced).map(([_, t], i) => { + testCase = t; + startCap = lineCaps[ + capsOptions[i % capsOptions.length] as keyof typeof lineCaps + ]; + endCap = lineCaps[ + capsOptions[ + (i + 3) % capsOptions.length // greater coverage + ] as keyof typeof lineCaps + ]; + join = lineJoins[ + joinOptions[i % joinOptions.length] as keyof typeof lineJoins + ]; + const namespace = tgpu['~unstable'].namespace(); + return Object.entries(createPipelines()).map(([_, pipeline]) => + root.device.createShaderModule({ + code: tgpu.resolve([pipeline], { + names: namespace, + }), + }) + ); + }); + + testCase = prevTestCase; + startCap = prevStartCap; + endCap = prevEndCap; + join = prevJoin; + showRadii = prevShowRadii; + }, + }, }; export function onCleanup() { root.destroy(); cancelAnimationFrame(frameId); } +// #endregion diff --git a/apps/typegpu-docs/src/examples/geometry/lines-combinations/testCases.ts b/apps/typegpu-docs/src/examples/geometry/lines-combinations/testCases.ts index 05f9f6351..0886136bd 100644 --- a/apps/typegpu-docs/src/examples/geometry/lines-combinations/testCases.ts +++ b/apps/typegpu-docs/src/examples/geometry/lines-combinations/testCases.ts @@ -19,10 +19,11 @@ const testCaseShell = tgpu.fn([u32, f32], LineSegmentVertex); const segmentSide = tgpu.const(arrayOf(f32, 4), [-1, -1, 1, 1]); -export const segmentAlternate = testCaseShell( +const segmentAlternate = testCaseShell( (vertexIndex, time) => { 'use gpu'; - const side = segmentSide.$[vertexIndex]; + // biome-ignore lint/style/useConst: cannot be const, right side has runtime origin + let side = segmentSide.$[vertexIndex]; const r = sin(time + select(0, Math.PI / 2, side === -1)); const radius = 0.4 * r * r; return LineSegmentVertex({ @@ -32,10 +33,11 @@ export const segmentAlternate = testCaseShell( }, ); -export const segmentStretch = testCaseShell( +const segmentStretch = testCaseShell( (vertexIndex, time) => { 'use gpu'; - const side = segmentSide.$[vertexIndex]; + // biome-ignore lint/style/useConst: cannot be const, right side has runtime origin + let side = segmentSide.$[vertexIndex]; const distance = 0.5 * clamp(0.55 * sin(1.5 * time) + 0.5, 0, 1); return LineSegmentVertex({ position: vec2f(distance * side * cos(time), distance * side * sin(time)), @@ -44,10 +46,11 @@ export const segmentStretch = testCaseShell( }, ); -export const segmentContainsAnotherEnd = testCaseShell( +const segmentContainsAnotherEnd = testCaseShell( (vertexIndex, time) => { 'use gpu'; - const side = segmentSide.$[vertexIndex]; + // biome-ignore lint/style/useConst: cannot be const, right side has runtime origin + let side = segmentSide.$[vertexIndex]; return LineSegmentVertex({ position: vec2f(side * 0.25 * (1 + clamp(sin(time), -0.8, 1)), 0), radius: 0.25 + side * 0.125, @@ -55,7 +58,7 @@ export const segmentContainsAnotherEnd = testCaseShell( }, ); -export const caseVShapeSmall = testCaseShell( +const caseVShapeSmall = testCaseShell( (vertexIndex, t) => { 'use gpu'; const side = clamp(f32(vertexIndex) - 2, -1, 1); @@ -67,7 +70,7 @@ export const caseVShapeSmall = testCaseShell( }, ); -export const caseVShapeBig = testCaseShell( +const caseVShapeBig = testCaseShell( (vertexIndex, time) => { 'use gpu'; const side = clamp(f32(vertexIndex) - 2, -1, 1); @@ -79,7 +82,7 @@ export const caseVShapeBig = testCaseShell( }, ); -export const halfCircle = testCaseShell( +const halfCircle = testCaseShell( (vertexIndex, time) => { 'use gpu'; const angle = Math.PI * clamp(f32(vertexIndex) - 1, 0, 50) / 50; @@ -91,7 +94,7 @@ export const halfCircle = testCaseShell( }, ); -export const halfCircleThin = testCaseShell( +const halfCircleThin = testCaseShell( (vertexIndex, time) => { 'use gpu'; const result = halfCircle(vertexIndex, time); @@ -100,7 +103,7 @@ export const halfCircleThin = testCaseShell( }, ); -export const bending = testCaseShell( +const bending = testCaseShell( (vertexIndex, time) => { 'use gpu'; const i = clamp(f32(vertexIndex) - 1, 0, 48) / 48; @@ -115,7 +118,7 @@ export const bending = testCaseShell( }, ); -export const animateWidth = testCaseShell( +const animateWidth = testCaseShell( (vertexIndex, time) => { 'use gpu'; const i = (f32(vertexIndex) % TEST_SEGMENT_COUNT) / TEST_SEGMENT_COUNT; @@ -128,7 +131,7 @@ export const animateWidth = testCaseShell( }, ); -export const perlinTraces = testCaseShell( +const perlinTraces = testCaseShell( (vertexIndex, time) => { 'use gpu'; const perLine = u32(200); @@ -153,7 +156,7 @@ export const perlinTraces = testCaseShell( }, ); -export const bars = testCaseShell( +const bars = testCaseShell( (vertexIndex, time) => { 'use gpu'; const VERTS_PER_LINE = u32(5); @@ -172,7 +175,7 @@ export const bars = testCaseShell( }, ); -export const arms = testCaseShell( +const arms = testCaseShell( (vertexIndex, time) => { 'use gpu'; const s = sin(time); @@ -192,7 +195,7 @@ export const arms = testCaseShell( }, ); -export const armsSmall = testCaseShell( +const armsSmall = testCaseShell( (vertexIndex, time) => { 'use gpu'; const result = arms(vertexIndex, time); @@ -203,7 +206,7 @@ export const armsSmall = testCaseShell( }, ); -export const armsBig = testCaseShell( +const armsBig = testCaseShell( (vertexIndex, time) => { 'use gpu'; const result = arms(vertexIndex, time); @@ -214,7 +217,7 @@ export const armsBig = testCaseShell( }, ); -export const armsRotating = testCaseShell( +const armsRotating = testCaseShell( (vertexIndex, time) => { 'use gpu'; const s = sin(time); @@ -234,7 +237,7 @@ export const armsRotating = testCaseShell( }, ); -export const flyingSquares = testCaseShell( +const flyingSquares = testCaseShell( (vertexIndex, time) => { 'use gpu'; const squareIndex = u32(vertexIndex / 8); @@ -265,3 +268,22 @@ export const flyingSquares = testCaseShell( }); }, ); + +export const testCases = { + animateWidth, + arms, + armsBig, + armsRotating, + armsSmall, + bars, + bending, + caseVShapeBig, + caseVShapeSmall, + flyingSquares, + halfCircle, + halfCircleThin, + perlinTraces, + segmentAlternate, + segmentContainsAnotherEnd, + segmentStretch, +}; diff --git a/apps/typegpu-docs/src/examples/simulation/wind-map/index.ts b/apps/typegpu-docs/src/examples/simulation/wind-map/index.ts index 9a7e8f121..71f156f7f 100644 --- a/apps/typegpu-docs/src/examples/simulation/wind-map/index.ts +++ b/apps/typegpu-docs/src/examples/simulation/wind-map/index.ts @@ -1,6 +1,8 @@ import { endCapSlot, joinSlot, + lineCaps, + lineJoins, lineSegmentIndicesCapLevel1, lineSegmentVariableWidth, LineSegmentVertex, @@ -18,7 +20,6 @@ import { vec2f, vec4f, } from 'typegpu/data'; -import { lineCaps, lineJoins } from '@typegpu/geometry'; import { add, clamp, mix, mul, normalize, select } from 'typegpu/std'; const root = await tgpu.init({ @@ -123,8 +124,8 @@ const advectCompute = tgpu['~unstable'].computeFn({ const v0 = vectorField(pos); const v1 = vectorField(add(pos, mul(v0, 0.5 * stepSize))); const newPos = add(pos, mul(v1, stepSize)); - particle.positions[currentPosIndex] = newPos; - bindGroupLayoutWritable.$.particles[particleIndex] = particle; + particle.positions[currentPosIndex] = vec2f(newPos); + bindGroupLayoutWritable.$.particles[particleIndex] = ParticleTrail(particle); }); const lineWidth = tgpu.fn([f32], f32)((x) => 0.004 * (1 - x)); @@ -284,6 +285,7 @@ const runAnimationFrame = () => { }; runAnimationFrame(); +// #region Example controls & Cleanup export const controls = { 'Play': { initial: true, @@ -298,3 +300,4 @@ export function onCleanup() { root.device.destroy(); cancelAnimationFrame(frameId); } +// #endregion diff --git a/packages/typegpu-geometry/src/circle.ts b/packages/typegpu-geometry/src/circle.ts index a7d459b64..0fac02eec 100644 --- a/packages/typegpu-geometry/src/circle.ts +++ b/packages/typegpu-geometry/src/circle.ts @@ -44,7 +44,7 @@ const getSubdivLevel = tgpu.fn([u32], SubdivLevelResult)( ); const consecutiveTriangleVertexIndex = tgpu.fn([u32], u32)((i) => { - return (2 * (i + 1)) / 3; + return u32((2 * (i + 1)) / 3); }); /** @@ -69,7 +69,7 @@ export const circle = tgpu.fn([u32], vec2f)( export function circleVertexCount(subdivLevel: number) { let totalVertexCount = 3; - for (let level = 0; level < subdivLevel; level += 1) { + for (let level = u32(0); level < subdivLevel; level += 1) { totalVertexCount += 9 * (1 << level); } return totalVertexCount; diff --git a/packages/typegpu-geometry/src/lines/caps/arrow.ts b/packages/typegpu-geometry/src/lines/caps/arrow.ts index a91c0221d..e864e70eb 100644 --- a/packages/typegpu-geometry/src/lines/caps/arrow.ts +++ b/packages/typegpu-geometry/src/lines/caps/arrow.ts @@ -28,7 +28,7 @@ export const arrowCap = capShell( if (joinPath.depth >= 0) { const remove = [v0, v4]; const dm = remove[joinPath.joinIndex & 0x1] as v2f; - return dm; + return vec2f(dm); } return points[vertexIndex % 5] as v2f; diff --git a/packages/typegpu-geometry/src/lines/caps/butt.ts b/packages/typegpu-geometry/src/lines/caps/butt.ts index 81c91b8a4..5ea3f9523 100644 --- a/packages/typegpu-geometry/src/lines/caps/butt.ts +++ b/packages/typegpu-geometry/src/lines/caps/butt.ts @@ -55,6 +55,6 @@ export const buttCap = capShell( const v3 = addMul(V.position, d, V.radius); const v4 = select(v3, vd, shouldJoin); const points = [v0, v1, v2, v3, v4]; - return points[vertexIndex % 5] as v2f; + return vec2f(points[vertexIndex % 5] as v2f); }, ); diff --git a/packages/typegpu-geometry/src/lines/caps/index.ts b/packages/typegpu-geometry/src/lines/caps/index.ts index 2b969d8b2..0d34dfe5f 100644 --- a/packages/typegpu-geometry/src/lines/caps/index.ts +++ b/packages/typegpu-geometry/src/lines/caps/index.ts @@ -1,9 +1,9 @@ +import { arrowCap } from './arrow.ts'; import { buttCap } from './butt.ts'; -import { squareCap } from './square.ts'; import { roundCap } from './round.ts'; -import { triangleCap } from './triangle.ts'; -import { arrowCap } from './arrow.ts'; +import { squareCap } from './square.ts'; import { swallowtailCap } from './swallowtail.ts'; +import { triangleCap } from './triangle.ts'; export const lineCaps = { butt: buttCap, diff --git a/packages/typegpu-geometry/src/lines/caps/round.ts b/packages/typegpu-geometry/src/lines/caps/round.ts index b2975cb66..eb9f618c4 100644 --- a/packages/typegpu-geometry/src/lines/caps/round.ts +++ b/packages/typegpu-geometry/src/lines/caps/round.ts @@ -1,4 +1,4 @@ -import type { v2f } from 'typegpu/data'; +import { type v2f, vec2f } from 'typegpu/data'; import { select } from 'typegpu/std'; import { addMul, bisectCcw, bisectNoCheck } from '../../utils.ts'; import { capShell } from './common.ts'; @@ -15,17 +15,17 @@ export const roundCap = capShell( left, ) => { 'use gpu'; - const uR = right; - const u = dir; - const c = dir; - const d = dir; - const dR = left; + const uR = vec2f(right); + const u = vec2f(dir); + const c = vec2f(dir); + const d = vec2f(dir); + const dR = vec2f(left); const joinIndex = joinPath.joinIndex; if (joinPath.depth >= 0) { const parents = [uR, u, d, dR]; - let d0 = parents[(joinIndex * 2) & 3] as v2f; - let d1 = parents[(joinIndex * 2 + 1) & 3] as v2f; + let d0 = vec2f(parents[(joinIndex * 2) & 3] as v2f); + let d1 = vec2f(parents[(joinIndex * 2 + 1) & 3] as v2f); let dm = bisectCcw(d0, d1); let path = joinPath.path; for (let depth = joinPath.depth; depth > 0; depth -= 1) { @@ -42,6 +42,6 @@ export const roundCap = capShell( const v2 = addMul(V.position, c, V.radius); const v3 = addMul(V.position, d, V.radius); const points = [vu, v1, v2, v3, vd]; - return points[vertexIndex % 5] as v2f; + return vec2f(points[vertexIndex % 5] as v2f); }, ); diff --git a/packages/typegpu-geometry/src/lines/caps/square.ts b/packages/typegpu-geometry/src/lines/caps/square.ts index 93accec54..a6618c8b0 100644 --- a/packages/typegpu-geometry/src/lines/caps/square.ts +++ b/packages/typegpu-geometry/src/lines/caps/square.ts @@ -1,4 +1,4 @@ -import type { v2f } from 'typegpu/data'; +import { type v2f, vec2f } from 'typegpu/data'; import { add, dot, select } from 'typegpu/std'; import { addMul, rot90ccw, rot90cw } from '../../utils.ts'; import { miterPointNoCheck } from '../utils.ts'; @@ -24,7 +24,7 @@ export const squareCap = capShell( add(dir, dirRight), shouldJoin, ); - const c = dir; + const c = vec2f(dir); const d = select( miterPointNoCheck(dir, left), add(dir, dirLeft), @@ -52,6 +52,6 @@ export const squareCap = capShell( const v2 = addMul(V.position, c, V.radius); const v3 = addMul(V.position, d, V.radius); const points = [vu, v1, v2, v3, vd]; - return points[vertexIndex % 5] as v2f; + return vec2f(points[vertexIndex % 5] as v2f); }, ); diff --git a/packages/typegpu-geometry/src/lines/caps/swallowtail.ts b/packages/typegpu-geometry/src/lines/caps/swallowtail.ts index 04dd7b22c..66655bea4 100644 --- a/packages/typegpu-geometry/src/lines/caps/swallowtail.ts +++ b/packages/typegpu-geometry/src/lines/caps/swallowtail.ts @@ -1,6 +1,6 @@ -import type { v2f } from 'typegpu/data'; -import { addMul, midPoint } from '../../utils.ts'; +import { type v2f, vec2f } from 'typegpu/data'; import { add } from 'typegpu/std'; +import { addMul, midPoint } from '../../utils.ts'; import { capShell } from './common.ts'; export const swallowtailCap = capShell( @@ -17,7 +17,7 @@ export const swallowtailCap = capShell( 'use gpu'; if (joinPath.depth >= 0) { const remove = [right, left]; - const dm = remove[joinPath.joinIndex & 0x1] as v2f; + const dm = vec2f(remove[joinPath.joinIndex & 0x1] as v2f); return addMul(V.position, dm, V.radius); } @@ -25,6 +25,6 @@ export const swallowtailCap = capShell( const v2 = addMul(V.position, midPoint(right, left), V.radius); const v3 = addMul(V.position, add(left, dir), V.radius); const points = [vu, v1, v2, v3, vd]; - return points[vertexIndex % 5] as v2f; + return vec2f(points[vertexIndex % 5] as v2f); }, ); diff --git a/packages/typegpu-geometry/src/lines/caps/triangle.ts b/packages/typegpu-geometry/src/lines/caps/triangle.ts index 1e43701ca..32c40ac58 100644 --- a/packages/typegpu-geometry/src/lines/caps/triangle.ts +++ b/packages/typegpu-geometry/src/lines/caps/triangle.ts @@ -1,4 +1,4 @@ -import type { v2f } from 'typegpu/data'; +import { type v2f, vec2f } from 'typegpu/data'; import { addMul } from '../../utils.ts'; import { capShell } from './common.ts'; @@ -16,7 +16,7 @@ export const triangleCap = capShell( 'use gpu'; if (joinPath.depth >= 0) { const remove = [right, left]; - const dm = remove[joinPath.joinIndex & 0x1] as v2f; + const dm = vec2f(remove[joinPath.joinIndex & 0x1] as v2f); return addMul(V.position, dm, V.radius); } @@ -24,6 +24,6 @@ export const triangleCap = capShell( const v2 = addMul(V.position, dir, V.radius); const v3 = addMul(V.position, left, V.radius); const points = [vu, v1, v2, v3, vd]; - return points[vertexIndex % 5] as v2f; + return vec2f(points[vertexIndex % 5] as v2f); }, ); diff --git a/packages/typegpu-geometry/src/lines/joins/common.ts b/packages/typegpu-geometry/src/lines/joins/common.ts index 9bc04dc9c..686e79d1d 100644 --- a/packages/typegpu-geometry/src/lines/joins/common.ts +++ b/packages/typegpu-geometry/src/lines/joins/common.ts @@ -2,8 +2,8 @@ import tgpu from 'typegpu'; import { bool, u32, vec2f } from 'typegpu/data'; import { dot } from 'typegpu/std'; import { cross2d } from '../../utils.ts'; -import { isCCW, rank3 } from '../utils.ts'; import { JoinPath, LineSegmentVertex } from '../types.ts'; +import { isCCW, rank3 } from '../utils.ts'; export const joinShell = tgpu.fn([ u32, diff --git a/packages/typegpu-geometry/src/lines/joins/miter.ts b/packages/typegpu-geometry/src/lines/joins/miter.ts index b2ed59962..d78a53426 100644 --- a/packages/typegpu-geometry/src/lines/joins/miter.ts +++ b/packages/typegpu-geometry/src/lines/joins/miter.ts @@ -19,7 +19,7 @@ export const miterLimit = tgpu.fn([vec2f, f32], vec2f)((miter, limitRatio) => { (limitRatio - 1) * (limitRatio * limitRatio - 1) / (m2 - 1) + 1, ); } - return miter; + return vec2f(miter); }); export const miterJoin = joinShell( @@ -53,35 +53,35 @@ export const miterJoin = joinShell( 0.5, ); - let uR = ur; - let u = miterU; + let uR = vec2f(ur); + let u = vec2f(miterU); let c = select(averageCenter, crossCenter, shouldCross); - let d = miterD; - let dR = dr; + let d = vec2f(miterD); + let dR = vec2f(dr); if (situationIndex === 2) { const mid = bisectCcw(ur, dr); - uR = ur; - u = mid; - c = mid; - d = mid; - dR = dr; + uR = vec2f(ur); + u = vec2f(mid); + c = vec2f(mid); + d = vec2f(mid); + dR = vec2f(dr); } if (situationIndex === 3) { const mid = bisectCcw(dl, ul); - uR = ur; - u = mid; - c = mid; - d = mid; - dR = dr; + uR = vec2f(ur); + u = vec2f(mid); + c = vec2f(mid); + d = vec2f(mid); + dR = vec2f(dr); } const joinIndex = joinPath.joinIndex; if (joinPath.depth >= 0) { const parents = [uR, u, d, dR]; - const d0 = parents[(joinIndex * 2) & 3] as v2f; - const d1 = parents[(joinIndex * 2 + 1) & 3] as v2f; + const d0 = vec2f(parents[(joinIndex * 2) & 3] as v2f); + const d1 = vec2f(parents[(joinIndex * 2 + 1) & 3] as v2f); const dm = miterPoint(d0, d1); return addMul(V.position, dm, V.radius); } @@ -90,6 +90,6 @@ export const miterJoin = joinShell( const v2 = select(vu, addMul(V.position, c, V.radius), joinU || joinD); const v3 = select(vd, addMul(V.position, d, V.radius), joinD); const points = [vu, v1, v2, v3, vd]; - return points[vertexIndex % 5] as v2f; + return vec2f(points[vertexIndex % 5] as v2f); }, ); diff --git a/packages/typegpu-geometry/src/lines/joins/round.ts b/packages/typegpu-geometry/src/lines/joins/round.ts index b77cc0bac..9a8687ede 100644 --- a/packages/typegpu-geometry/src/lines/joins/round.ts +++ b/packages/typegpu-geometry/src/lines/joins/round.ts @@ -1,4 +1,4 @@ -import type { v2f } from 'typegpu/data'; +import { type v2f, vec2f } from 'typegpu/data'; import { add, mul, select } from 'typegpu/std'; import { addMul, bisectCcw, bisectNoCheck } from '../../utils.ts'; import { intersectLines } from '../utils.ts'; @@ -35,33 +35,33 @@ export const roundJoin = joinShell( 0.25, ); - let uR = ur; - let u = midU; + let uR = vec2f(ur); + let u = vec2f(midU); let c = select(averageCenter, crossCenter, shouldCross); - let d = midD; - let dR = dr; + let d = vec2f(midD); + let dR = vec2f(dr); if (situationIndex === 2) { - uR = ur; - u = midR; - c = midR; - d = midR; - dR = dr; + uR = vec2f(ur); + u = vec2f(midR); + c = vec2f(midR); + d = vec2f(midR); + dR = vec2f(dr); } if (situationIndex === 3) { - uR = ur; - u = midL; - c = midL; - d = midL; - dR = dr; + uR = vec2f(ur); + u = vec2f(midL); + c = vec2f(midL); + d = vec2f(midL); + dR = vec2f(dr); } const joinIndex = joinPath.joinIndex; if (joinPath.depth >= 0) { const parents = [uR, u, d, dR]; - let d0 = parents[(joinIndex * 2) & 3] as v2f; - let d1 = parents[(joinIndex * 2 + 1) & 3] as v2f; + let d0 = vec2f(parents[(joinIndex * 2) & 3] as v2f); + let d1 = vec2f(parents[(joinIndex * 2 + 1) & 3] as v2f); let dm = bisectCcw(d0, d1); let path = joinPath.path; for (let depth = joinPath.depth; depth > 0; depth -= 1) { diff --git a/packages/typegpu-geometry/src/lines/lines.ts b/packages/typegpu-geometry/src/lines/lines.ts index 64de96c08..2ceeedb94 100644 --- a/packages/typegpu-geometry/src/lines/lines.ts +++ b/packages/typegpu-geometry/src/lines/lines.ts @@ -1,14 +1,14 @@ import tgpu from 'typegpu'; -import { struct, u32, vec2f } from 'typegpu/data'; import type { v2f } from 'typegpu/data'; +import { struct, u32, vec2f } from 'typegpu/data'; import { dot, mul, normalize, sub } from 'typegpu/std'; import { addMul, midPoint, rot90ccw, rot90cw } from '../utils.ts'; -import { externalNormals, limitTowardsMiddle, miterPoint } from './utils.ts'; -import { JoinPath, LineSegmentVertex } from './types.ts'; -import { joinSituationIndex } from './joins/common.ts'; -import { roundJoin } from './joins/round.ts'; import { roundCap } from './caps/round.ts'; import { JOIN_LIMIT } from './constants.ts'; +import { joinSituationIndex } from './joins/common.ts'; +import { roundJoin } from './joins/round.ts'; +import { JoinPath, LineSegmentVertex } from './types.ts'; +import { externalNormals, limitTowardsMiddle, miterPoint } from './utils.ts'; export const joinSlot = tgpu.slot(roundJoin); export const startCapSlot = tgpu.slot(roundCap); @@ -18,7 +18,7 @@ const getJoinParent = tgpu.fn([u32], u32)((i) => (i - 4) >> 1); const getJoinVertexPath = tgpu.fn([u32], JoinPath)((vertexIndex) => { // deno-fmt-ignore - const lookup = [u32(0), u32(0), /* dont care */u32(0), u32(1), u32(1), u32(2), u32(2), /* dont care */u32(2), u32(3), u32(3)]; + const lookup = [u32(0), u32(0), /* dont care */ u32(0), u32(1), u32(1), u32(2), u32(2), /* dont care */ u32(2), u32(3), u32(3)]; if (vertexIndex < 10) { return JoinPath({ joinIndex: lookup[vertexIndex] as number, @@ -79,10 +79,10 @@ export const lineSegmentVariableWidth = tgpu.fn([ const nBC = normalize(BC); const nCB = mul(nBC, -1); - let d0 = eBC.n1; - let d4 = eBC.n2; - let d5 = eBC.n2; - let d9 = eBC.n1; + let d0 = vec2f(eBC.n1); + let d4 = vec2f(eBC.n2); + let d5 = vec2f(eBC.n2); + let d9 = vec2f(eBC.n1); const situationIndexB = joinSituationIndex(eAB.n1, eBC.n1, eAB.n2, eBC.n2); const situationIndexC = joinSituationIndex(eCD.n2, eBC.n2, eCD.n1, eBC.n1); @@ -134,35 +134,35 @@ export const lineSegmentVariableWidth = tgpu.fn([ const limU = limitTowardsMiddle(midBC, tBC1, v0, v9); const limD = limitTowardsMiddle(midBC, tBC2, v4, v5); - v0 = limU.a; - v9 = limU.b; - v4 = limD.a; - v5 = limD.b; + v0 = vec2f(limU.a); + v9 = vec2f(limU.b); + v4 = vec2f(limD.a); + v5 = vec2f(limD.b); // after this point we need to process only one of the joins! const isCSide = joinPath.joinIndex >= 2; let situationIndex = situationIndexB; - let V = B; + let V = LineSegmentVertex(B); let isCap = isCapB; - let j1 = eAB.n1; - let j2 = eBC.n1; - let j3 = eAB.n2; - let j4 = eBC.n2; - let vu = v0; - let vd = v4; + let j1 = vec2f(eAB.n1); + let j2 = vec2f(eBC.n1); + let j3 = vec2f(eAB.n2); + let j4 = vec2f(eBC.n2); + let vu = vec2f(v0); + let vd = vec2f(v4); let joinU = joinBu; let joinD = joinBd; if (isCSide) { situationIndex = situationIndexC; - V = C; + V = LineSegmentVertex(C); isCap = isCapC; - j4 = eBC.n1; - j3 = eCD.n1; - j2 = eBC.n2; - j1 = eCD.n2; - vu = v5; - vd = v9; + j4 = vec2f(eBC.n1); + j3 = vec2f(eCD.n1); + j2 = vec2f(eBC.n2); + j1 = vec2f(eCD.n2); + vu = vec2f(v5); + vd = vec2f(v9); joinU = joinCd; joinD = joinCu; } diff --git a/packages/typegpu-geometry/src/lines/types.ts b/packages/typegpu-geometry/src/lines/types.ts index 0be8e1846..d176a06de 100644 --- a/packages/typegpu-geometry/src/lines/types.ts +++ b/packages/typegpu-geometry/src/lines/types.ts @@ -1,5 +1,5 @@ -import { f32, i32, struct, u32, vec2f } from 'typegpu/data'; import type { Infer } from 'typegpu/data'; +import { f32, i32, struct, u32, vec2f } from 'typegpu/data'; export type JoinPath = Infer; export const JoinPath = struct({ diff --git a/packages/typegpu-geometry/src/lines/utils.ts b/packages/typegpu-geometry/src/lines/utils.ts index d3e649634..3827058fc 100644 --- a/packages/typegpu-geometry/src/lines/utils.ts +++ b/packages/typegpu-geometry/src/lines/utils.ts @@ -134,7 +134,7 @@ export const projectToLineSegment = tgpu.fn([vec2f, vec2f, vec2f], vec2f)( const AB = sub(B, A); const t = clamp(dot(p, AB) / dot(AB, AB), 0, 1); const projP = addMul(A, AB, t); - return projP; + return vec2f(projP); }, ); diff --git a/packages/typegpu/tests/examples/individual/circles.test.ts b/packages/typegpu/tests/examples/individual/circles.test.ts new file mode 100644 index 000000000..342b3bc6f --- /dev/null +++ b/packages/typegpu/tests/examples/individual/circles.test.ts @@ -0,0 +1,95 @@ +/** + * @vitest-environment jsdom + */ + +import { describe, expect } from 'vitest'; +import { it } from '../../utils/extendedIt.ts'; +import { runExampleTest, setupCommonMocks } from '../utils/baseTest.ts'; +import { mockResizeObserver } from '../utils/commonMocks.ts'; + +describe('circles example', () => { + setupCommonMocks(); + + it('should produce valid code', async ({ device }) => { + const shaderCodes = await runExampleTest({ + category: 'geometry', + name: 'circles', + setupMocks: mockResizeObserver, + expectedCalls: 1, + }, device); + + expect(shaderCodes).toMatchInlineSnapshot(` + "struct Circle_2 { + position: vec2f, + radius: f32, + } + + @group(0) @binding(0) var circles_1: array; + + struct SubdivLevelResult_5 { + level: u32, + pointCount: u32, + vertexCountInLevel: u32, + vertexIndexInLevel: u32, + } + + fn getSubdivLevel_4(vertexIndex: u32) -> SubdivLevelResult_5 { + var totalVertexCount = 0u; + for (var level = 0u; (level < 8u); level += 1u) { + let pointCount = (3u * (1u << level)); + let triangleCount = select(1u, (3u * (1u << (level - 1u))), (level > 0u)); + let vertexCountInLevel = (3u * triangleCount); + let newVertexCount = (totalVertexCount + vertexCountInLevel); + if ((vertexIndex < newVertexCount)) { + return SubdivLevelResult_5(level, pointCount, vertexCountInLevel, (vertexIndex - totalVertexCount)); + } + totalVertexCount = newVertexCount; + } + return SubdivLevelResult_5(0u, 0u, 0u, 0u); + } + + fn consecutiveTriangleVertexIndex_6(i: u32) -> u32 { + return u32((f32((2u * (i + 1u))) / 3f)); + } + + const PI_7: f32 = 3.141592653589793f; + + fn circle_3(vertexIndex: u32) -> vec2f { + var subdiv = getSubdivLevel_4(vertexIndex); + let i = consecutiveTriangleVertexIndex_6(subdiv.vertexIndexInLevel); + let pointCount = subdiv.pointCount; + let angle = (((2f * PI_7) * f32(i)) / f32(pointCount)); + return vec2f(cos(angle), sin(angle)); + } + + struct mainVertexMaxArea_Output_8 { + @builtin(position) outPos: vec4f, + @location(0) uv: vec2f, + @location(1) @interpolate(flat) instanceIndex: u32, + } + + struct mainVertexMaxArea_Input_9 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn mainVertexMaxArea_0(_arg_0: mainVertexMaxArea_Input_9) -> mainVertexMaxArea_Output_8 { + let C = (&circles_1[_arg_0.instanceIndex]); + var unit = circle_3(_arg_0.vertexIndex); + var pos = ((*C).position + (unit * (*C).radius)); + return mainVertexMaxArea_Output_8(vec4f(pos, 0f, 1f), unit, _arg_0.instanceIndex); + } + + struct mainFragment_Input_11 { + @location(0) uv: vec2f, + @location(1) @interpolate(flat) instanceIndex: u32, + } + + @fragment fn mainFragment_10(_arg_0: mainFragment_Input_11) -> @location(0) vec4f { + var color = vec3f(1f, cos(f32(_arg_0.instanceIndex)), sin((5f * f32(_arg_0.instanceIndex)))); + let r = length(_arg_0.uv); + return vec4f(mix(color, vec3f(), clamp(((r - 0.9f) * 20f), 0f, 0.5f)), 1f); + }" + `); + }); +}); diff --git a/packages/typegpu/tests/examples/individual/global-wind-map.test.ts b/packages/typegpu/tests/examples/individual/global-wind-map.test.ts new file mode 100644 index 000000000..d32adf320 --- /dev/null +++ b/packages/typegpu/tests/examples/individual/global-wind-map.test.ts @@ -0,0 +1,490 @@ +/** + * @vitest-environment jsdom + */ + +import { describe, expect } from 'vitest'; +import { it } from '../../utils/extendedIt.ts'; +import { runExampleTest, setupCommonMocks } from '../utils/baseTest.ts'; + +describe('global wind map example', () => { + setupCommonMocks(); + + it('should produce valid code', async ({ device }) => { + const shaderCodes = await runExampleTest({ + category: 'simulation', + name: 'wind-map', + expectedCalls: 2, + }, device); + + expect(shaderCodes).toMatchInlineSnapshot(` + "struct Uniforms_2 { + stepSize: f32, + frameCount: u32, + } + + @group(0) @binding(0) var uniforms_1: Uniforms_2; + + struct ParticleTrail_4 { + positions: array, + } + + @group(0) @binding(1) var particles_3: array; + + fn vectorField_5(pos: vec2f) -> vec2f { + return normalize(vec2f(-(pos.y), pos.x)); + } + + struct advectCompute_Input_6 { + @builtin(global_invocation_id) globalInvocationId: vec3u, + } + + @compute @workgroup_size(64) fn advectCompute_0(_arg_0: advectCompute_Input_6) { + let stepSize = uniforms_1.stepSize; + let frameCount2 = uniforms_1.frameCount; + let particleIndex = _arg_0.globalInvocationId.x; + let particle = (&particles_3[particleIndex]); + let currentPosIndex = (frameCount2 % 20u); + let prevPosIndex = (((20u + frameCount2) - 1u) % 20u); + let pos = (&(*particle).positions[prevPosIndex]); + var v0 = vectorField_5((*pos)); + var v1 = vectorField_5(((*pos) + (v0 * (0.5f * stepSize)))); + var newPos = ((*pos) + (v1 * stepSize)); + (*particle).positions[currentPosIndex] = newPos; + particles_3[particleIndex] = (*particle); + } + + struct Uniforms_2 { + stepSize: f32, + frameCount: u32, + } + + @group(0) @binding(0) var uniforms_1: Uniforms_2; + + struct mainVertex_Output_3 { + @builtin(position) outPos: vec4f, + @location(0) position: vec2f, + @location(1) trailPosition: f32, + } + + struct ParticleTrail_5 { + positions: array, + } + + @group(0) @binding(1) var particles_4: array; + + fn lineWidth_6(x: f32) -> f32 { + return (4e-3f * (1f - x)); + } + + struct LineSegmentVertex_7 { + position: vec2f, + radius: f32, + } + + struct JoinPath_10 { + joinIndex: u32, + path: u32, + depth: i32, + } + + fn getJoinParent_11(i: u32) -> u32 { + return ((i - 4u) >> 1u); + } + + fn getJoinVertexPath_9(vertexIndex: u32) -> JoinPath_10 { + var lookup = array(0u, 0u, 0u, 1u, 1u, 2u, 2u, 2u, 3u, 3u); + if ((vertexIndex < 10u)) { + return JoinPath_10(lookup[vertexIndex], 0u, -1i); + } + var joinIndex = (vertexIndex - 10u); + var depth = 0; + var path = 0u; + while ((joinIndex >= 4u)) { + path = ((path << 1u) | (joinIndex & 1u)); + joinIndex = getJoinParent_11(joinIndex); + depth += 1i; + } + return JoinPath_10(joinIndex, path, depth); + } + + struct LineSegmentOutput_12 { + vertexPosition: vec2f, + situationIndex: u32, + } + + struct ExternalNormals_14 { + n1: vec2f, + n2: vec2f, + } + + fn externalNormals_13(distance: vec2f, r1: f32, r2: f32) -> ExternalNormals_14 { + var dNorm = normalize(distance); + let expCos = ((r1 - r2) / length(distance)); + let expSin = sqrt(max(0f, (1f - (expCos * expCos)))); + let a = (dNorm.x * expCos); + let b = (dNorm.y * expSin); + let c = (dNorm.x * expSin); + let d = (dNorm.y * expCos); + var n1 = vec2f((a - b), (c + d)); + var n2 = vec2f((a + b), (-(c) + d)); + return ExternalNormals_14(n1, n2); + } + + fn cross2d_16(a: vec2f, b: vec2f) -> f32 { + return ((a.x * b.y) - (a.y * b.x)); + } + + fn isCCW_17(aX: f32, aYSign: bool, bX: f32, bYSign: bool) -> bool { + let sameSide = (aYSign == bYSign); + return select(aYSign, (aYSign == (aX >= bX)), sameSide); + } + + const lookup_19: array = array(5u, 3u, 4u, 3u, 2u, 1u, 0u, 0u); + + fn rank3_18(aGb: bool, bGc: bool, aGc: bool) -> u32 { + let code = (((u32(aGb) << 2u) | (u32(bGc) << 1u)) | u32(aGc)); + return lookup_19[code]; + } + + fn joinSituationIndex_15(ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f) -> u32 { + let crossUL = cross2d_16(ur, ul); + let crossDL = cross2d_16(ur, dl); + let crossDR = cross2d_16(ur, dr); + let signUL = (crossUL >= 0f); + let signDL = (crossDL >= 0f); + let signDR = (crossDR >= 0f); + let dotUL = dot(ur, ul); + let dotDL = dot(ur, dl); + let dotDR = dot(ur, dr); + return rank3_18(isCCW_17(dotUL, signUL, dotDL, signDL), isCCW_17(dotDL, signDL, dotDR, signDR), isCCW_17(dotUL, signUL, dotDR, signDR)); + } + + const JOIN_LIMIT_20: f32 = 0.999f; + + fn rot90ccw_23(v: vec2f) -> vec2f { + return vec2f(-(v.y), v.x); + } + + fn rot90cw_24(v: vec2f) -> vec2f { + return vec2f(v.y, -(v.x)); + } + + fn bisectCcw_22(a: vec2f, b: vec2f) -> vec2f { + let sin = cross2d_16(a, b); + let sinSign = select(-1f, 1f, (sin >= 0f)); + var orthoA = rot90ccw_23(a); + var orthoB = rot90cw_24(b); + var dir = select(((a + b) * sinSign), (orthoA + orthoB), (dot(a, b) < 0f)); + return normalize(dir); + } + + fn midPoint_25(a: vec2f, b: vec2f) -> vec2f { + return (0.5 * (a + b)); + } + + fn addMul_26(a: vec2f, b: vec2f, f: f32) -> vec2f { + return (a + (b * f)); + } + + fn miterPoint_21(a: vec2f, b: vec2f) -> vec2f { + let sin_ = cross2d_16(a, b); + var bisection = bisectCcw_22(a, b); + let b2 = dot(b, b); + let cos_ = dot(a, b); + let diff = (b2 - cos_); + if (((diff * diff) < 1e-4f)) { + return midPoint_25(a, b); + } + if ((sin_ < 0f)) { + return (bisection * -1000000); + } + let t = (diff / sin_); + return addMul_26(a, rot90ccw_23(a), t); + } + + struct LimitAlongResult_28 { + a: vec2f, + b: vec2f, + limitWasHit: bool, + } + + fn limitTowardsMiddle_27(middle: vec2f, dir: vec2f, p1: vec2f, p2: vec2f) -> LimitAlongResult_28 { + let t1 = dot((p1 - middle), dir); + let t2 = dot((p2 - middle), dir); + if ((t1 <= t2)) { + return LimitAlongResult_28(p1, p2, false); + } + let t = clamp((t1 / (t1 - t2)), 0f, 1f); + var p = mix(p1, p2, t); + return LimitAlongResult_28(p, p, true); + } + + fn intersectTangent_30(a: vec2f, n: vec2f) -> vec2f { + let cos_ = dot(a, n); + return (n * (1f / cos_)); + } + + fn miterPointNoCheck_31(a: vec2f, b: vec2f) -> vec2f { + var ab = (a + b); + return (ab * (2f / dot(ab, ab))); + } + + fn item_29(vertexIndex: u32, joinPath: JoinPath_10, V: LineSegmentVertex_7, vu: vec2f, vd: vec2f, right: vec2f, dir: vec2f, left: vec2f) -> vec2f { + let shouldJoin = (dot(dir, right) < 0f); + var dirRight = rot90cw_24(dir); + var dirLeft = rot90ccw_23(dir); + var u = select(intersectTangent_30(right, dirRight), dirRight, shouldJoin); + var c = vec2f(); + var d = select(intersectTangent_30(left, dirLeft), dirLeft, shouldJoin); + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var miterR = select(u, miterPointNoCheck_31(right, dirRight), shouldJoin); + var miterL = select(d, miterPointNoCheck_31(dirLeft, left), shouldJoin); + var parents = array(miterR, miterL); + let dm = (&parents[(joinIndex & 1u)]); + return addMul_26(V.position, (*dm), V.radius); + } + var v1 = addMul_26(V.position, u, V.radius); + var v0 = select(v1, vu, shouldJoin); + var v2 = addMul_26(V.position, c, V.radius); + var v3 = addMul_26(V.position, d, V.radius); + var v4 = select(v3, vd, shouldJoin); + var points = array(v0, v1, v2, v3, v4); + return points[(vertexIndex % 5u)]; + } + + fn item_32(vertexIndex: u32, joinPath: JoinPath_10, V: LineSegmentVertex_7, vu: vec2f, vd: vec2f, _right: vec2f, dir: vec2f, _left: vec2f) -> vec2f { + var dirRight = rot90cw_24(dir); + var dirLeft = rot90ccw_23(dir); + var v0 = addMul_26(vu, dir, (-7.5f * V.radius)); + var v1 = addMul_26(V.position, addMul_26(dirRight, dir, -3f), (3f * V.radius)); + var v2 = addMul_26(V.position, vec2f(), (2f * V.radius)); + var v3 = addMul_26(V.position, addMul_26(dirLeft, dir, -3f), (3f * V.radius)); + var v4 = addMul_26(vd, dir, (-7.5f * V.radius)); + var points = array(v0, v1, v2, v3, v4); + if ((joinPath.depth >= 0i)) { + var remove = array(v0, v4); + let dm = (&remove[(joinPath.joinIndex & 1u)]); + return (*dm); + } + return points[(vertexIndex % 5u)]; + } + + struct Intersection_35 { + valid: bool, + t: f32, + point: vec2f, + } + + fn intersectLines_34(A1: vec2f, A2: vec2f, B1: vec2f, B2: vec2f) -> Intersection_35 { + var a = (A2 - A1); + var b = (B2 - B1); + let axb = cross2d_16(a, b); + var AB = (B1 - A1); + let t = (cross2d_16(AB, b) / axb); + return Intersection_35((axb != 0f), t, addMul_26(A1, a, t)); + } + + fn bisectNoCheck_36(a: vec2f, b: vec2f) -> vec2f { + return normalize((a + b)); + } + + fn item_33(situationIndex: u32, vertexIndex: u32, joinPath: JoinPath_10, V: LineSegmentVertex_7, vu: vec2f, vd: vec2f, ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f, joinU: bool, joinD: bool) -> vec2f { + var midU = bisectCcw_22(ur, ul); + var midD = bisectCcw_22(dl, dr); + var midR = bisectCcw_22(ur, dr); + var midL = bisectCcw_22(dl, ul); + let shouldCross = ((situationIndex == 1u) || (situationIndex == 4u)); + var crossCenter = intersectLines_34(ul, dl, ur, dr).point; + var averageCenter = (((ur + ul) + (dl + dr)) * 0.25); + var uR = ur; + var u = midU; + var c = select(averageCenter, crossCenter, shouldCross); + var d = midD; + var dR = dr; + if ((situationIndex == 2u)) { + uR = ur; + u = midR; + c = midR; + d = midR; + dR = dr; + } + if ((situationIndex == 3u)) { + uR = ur; + u = midL; + c = midL; + d = midL; + dR = dr; + } + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = bisectCcw_22(d0, d1); + var path = joinPath.path; + for (var depth = joinPath.depth; (depth > 0i); depth -= 1i) { + let isLeftChild = ((path & 1u) == 0u); + d0 = select(dm, d0, isLeftChild); + d1 = select(d1, dm, isLeftChild); + dm = bisectNoCheck_36(d0, d1); + path >>= 1u; + } + return addMul_26(V.position, dm, V.radius); + } + var v1 = select(vu, addMul_26(V.position, u, V.radius), joinU); + var v2 = select(vu, addMul_26(V.position, c, V.radius), (joinU || joinD)); + var v3 = select(vd, addMul_26(V.position, d, V.radius), joinD); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn lineSegmentVariableWidth_8(vertexIndex: u32, A: LineSegmentVertex_7, B: LineSegmentVertex_7, C: LineSegmentVertex_7, D: LineSegmentVertex_7) -> LineSegmentOutput_12 { + var joinPath = getJoinVertexPath_9(vertexIndex); + var AB = (B.position - A.position); + var BC = (C.position - B.position); + var CD = (D.position - C.position); + let radiusABDelta = (A.radius - B.radius); + let radiusBCDelta = (B.radius - C.radius); + let radiusCDDelta = (C.radius - D.radius); + if ((dot(BC, BC) <= (radiusBCDelta * radiusBCDelta))) { + return LineSegmentOutput_12(vec2f(), 0u); + } + let isCapB = (dot(AB, AB) <= ((radiusABDelta * radiusABDelta) + 1e-12f)); + let isCapC = (dot(CD, CD) <= ((radiusCDDelta * radiusCDDelta) + 1e-12f)); + var eAB = externalNormals_13(AB, A.radius, B.radius); + var eBC = externalNormals_13(BC, B.radius, C.radius); + var eCD = externalNormals_13(CD, C.radius, D.radius); + var nBC = normalize(BC); + var nCB = (nBC * -1); + var d0 = eBC.n1; + var d4 = eBC.n2; + var d5 = eBC.n2; + var d9 = eBC.n1; + let situationIndexB = joinSituationIndex_15(eAB.n1, eBC.n1, eAB.n2, eBC.n2); + let situationIndexC = joinSituationIndex_15(eCD.n2, eBC.n2, eCD.n1, eBC.n1); + var joinBu = true; + var joinBd = true; + var joinCu = true; + var joinCd = true; + if (!isCapB) { + if ((((situationIndexB == 1u) || (situationIndexB == 5u)) || (dot(eBC.n2, eAB.n2) > JOIN_LIMIT_20))) { + d4 = miterPoint_21(eBC.n2, eAB.n2); + joinBd = false; + } + if ((((situationIndexB == 4u) || (situationIndexB == 5u)) || (dot(eAB.n1, eBC.n1) > JOIN_LIMIT_20))) { + d0 = miterPoint_21(eAB.n1, eBC.n1); + joinBu = false; + } + } + if (!isCapC) { + if ((((situationIndexC == 4u) || (situationIndexC == 5u)) || (dot(eCD.n2, eBC.n2) > JOIN_LIMIT_20))) { + d5 = miterPoint_21(eCD.n2, eBC.n2); + joinCd = false; + } + if ((((situationIndexC == 1u) || (situationIndexC == 5u)) || (dot(eBC.n1, eCD.n1) > JOIN_LIMIT_20))) { + d9 = miterPoint_21(eBC.n1, eCD.n1); + joinCu = false; + } + } + var v0 = addMul_26(B.position, d0, B.radius); + var v4 = addMul_26(B.position, d4, B.radius); + var v5 = addMul_26(C.position, d5, C.radius); + var v9 = addMul_26(C.position, d9, C.radius); + var midBC = midPoint_25(B.position, C.position); + var tBC1 = rot90cw_24(eBC.n1); + var tBC2 = rot90ccw_23(eBC.n2); + var limU = limitTowardsMiddle_27(midBC, tBC1, v0, v9); + var limD = limitTowardsMiddle_27(midBC, tBC2, v4, v5); + v0 = limU.a; + v9 = limU.b; + v4 = limD.a; + v5 = limD.b; + let isCSide = (joinPath.joinIndex >= 2u); + var situationIndex = situationIndexB; + var V = B; + var isCap = isCapB; + var j1 = eAB.n1; + var j2 = eBC.n1; + var j3 = eAB.n2; + var j4 = eBC.n2; + var vu = v0; + var vd = v4; + var joinU = joinBu; + var joinD = joinBd; + if (isCSide) { + situationIndex = situationIndexC; + V = C; + isCap = isCapC; + j4 = eBC.n1; + j3 = eCD.n1; + j2 = eBC.n2; + j1 = eCD.n2; + vu = v5; + vd = v9; + joinU = joinCd; + joinD = joinCu; + } + let joinIndex = joinPath.joinIndex; + if ((vertexIndex >= 10u)) { + var shouldJoin = array(u32(joinBu), u32(joinBd), u32(joinCd), u32(joinCu)); + if ((shouldJoin[joinIndex] == 0u)) { + var noJoinPoints = array(v0, v4, v5, v9); + let vertexPosition2 = (&noJoinPoints[joinIndex]); + return LineSegmentOutput_12((*vertexPosition2), situationIndex); + } + } + var vertexPosition = vec2f(); + if (isCap) { + if (isCSide) { + vertexPosition = item_29(vertexIndex, joinPath, V, vu, vd, j2, nBC, j4); + } + else { + vertexPosition = item_32(vertexIndex, joinPath, V, vu, vd, j2, nCB, j4); + } + } + else { + vertexPosition = item_33(situationIndex, vertexIndex, joinPath, V, vu, vd, j1, j2, j3, j4, joinU, joinD); + } + return LineSegmentOutput_12(vertexPosition, situationIndex); + } + + struct mainVertex_Input_37 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn mainVertex_0(_arg_0: mainVertex_Input_37) -> mainVertex_Output_3 { + let frameCount2 = uniforms_1.frameCount; + let particleIndex = u32((f32(_arg_0.instanceIndex) / 20f)); + let trailIndexOriginal = (_arg_0.instanceIndex % 20u); + let currentPosIndex = (frameCount2 % 20u); + let trailIndex = (i32(((20u + currentPosIndex) - trailIndexOriginal)) % 20i); + if ((trailIndexOriginal == 19u)) { + return mainVertex_Output_3(vec4f(), vec2f(), 0f); + } + let particle = (&particles_4[particleIndex]); + let iA = select(((trailIndex + 1i) % 20i), trailIndex, (trailIndexOriginal == 0u)); + let iB = trailIndex; + let iC = (((20i + trailIndex) - 1i) % 20i); + let iD = (((20i + trailIndex) - 2i) % 20i); + var A = LineSegmentVertex_7((*particle).positions[iA], lineWidth_6((f32(trailIndexOriginal) / 19f))); + var B = LineSegmentVertex_7((*particle).positions[iB], lineWidth_6((f32((trailIndexOriginal + 1u)) / 19f))); + var C = LineSegmentVertex_7((*particle).positions[iC], lineWidth_6((f32((trailIndexOriginal + 2u)) / 19f))); + var D = LineSegmentVertex_7((*particle).positions[iD], lineWidth_6((f32((trailIndexOriginal + 3u)) / 19f))); + var result = lineSegmentVariableWidth_8(_arg_0.vertexIndex, A, B, C, D); + return mainVertex_Output_3(vec4f(result.vertexPosition, 0f, 1f), result.vertexPosition, (f32(trailIndexOriginal) / 19f)); + } + + struct mainFragment_Input_39 { + @location(0) position: vec2f, + @location(1) trailPosition: f32, + } + + @fragment fn mainFragment_38(_arg_0: mainFragment_Input_39) -> @location(0) vec4f { + let opacity = clamp((3f * (1f - _arg_0.trailPosition)), 0f, 1f); + return mix(vec4f(0.77f, 0.39f, 1f, opacity), vec4f(0.11f, 0.44f, 0.94f, opacity), ((_arg_0.position.x * 0.5f) + 0.5f)); + }" + `); + }); +}); diff --git a/packages/typegpu/tests/examples/individual/lines-combinations.test.ts b/packages/typegpu/tests/examples/individual/lines-combinations.test.ts new file mode 100644 index 000000000..12277bb1e --- /dev/null +++ b/packages/typegpu/tests/examples/individual/lines-combinations.test.ts @@ -0,0 +1,2367 @@ +/** + * @vitest-environment jsdom + */ + +import { describe, expect } from 'vitest'; +import { it } from '../../utils/extendedIt.ts'; +import { runExampleTest, setupCommonMocks } from '../utils/baseTest.ts'; + +describe('lines combinations example', () => { + setupCommonMocks(); + + it('should produce valid code', async ({ device }) => { + const shaderCodes = await runExampleTest({ + category: 'geometry', + name: 'lines-combinations', + expectedCalls: 14, + controlTriggers: ['Test Resolution'], + }, device); + + expect(shaderCodes).toMatchInlineSnapshot(` + "struct Uniforms_2 { + time: f32, + fillType: u32, + } + + @group(0) @binding(0) var uniforms_1: Uniforms_2; + + struct LineSegmentVertex_4 { + position: vec2f, + radius: f32, + } + + fn item_3(vertexIndex: u32, time: f32) -> LineSegmentVertex_4 { + let s = sin(time); + let c = cos(time); + const r = 0.25; + var points = array(vec2f(((r * s) - 0.25f), (r * c)), vec2f(-0.25, 0), vec2f(0.25, 0), vec2f(((-(r) * s) + 0.25f), (r * c))); + let i = clamp((i32(vertexIndex) - 1i), 0i, 3i); + return LineSegmentVertex_4(points[i], 0.2f); + } + + struct mainVertex_Output_5 { + @builtin(position) outPos: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + } + + struct JoinPath_8 { + joinIndex: u32, + path: u32, + depth: i32, + } + + fn getJoinParent_9(i: u32) -> u32 { + return ((i - 4u) >> 1u); + } + + fn getJoinVertexPath_7(vertexIndex: u32) -> JoinPath_8 { + var lookup = array(0u, 0u, 0u, 1u, 1u, 2u, 2u, 2u, 3u, 3u); + if ((vertexIndex < 10u)) { + return JoinPath_8(lookup[vertexIndex], 0u, -1i); + } + var joinIndex = (vertexIndex - 10u); + var depth = 0; + var path = 0u; + while ((joinIndex >= 4u)) { + path = ((path << 1u) | (joinIndex & 1u)); + joinIndex = getJoinParent_9(joinIndex); + depth += 1i; + } + return JoinPath_8(joinIndex, path, depth); + } + + struct LineSegmentOutput_10 { + vertexPosition: vec2f, + situationIndex: u32, + } + + struct ExternalNormals_12 { + n1: vec2f, + n2: vec2f, + } + + fn externalNormals_11(distance: vec2f, r1: f32, r2: f32) -> ExternalNormals_12 { + var dNorm = normalize(distance); + let expCos = ((r1 - r2) / length(distance)); + let expSin = sqrt(max(0f, (1f - (expCos * expCos)))); + let a = (dNorm.x * expCos); + let b = (dNorm.y * expSin); + let c = (dNorm.x * expSin); + let d = (dNorm.y * expCos); + var n1 = vec2f((a - b), (c + d)); + var n2 = vec2f((a + b), (-(c) + d)); + return ExternalNormals_12(n1, n2); + } + + fn cross2d_14(a: vec2f, b: vec2f) -> f32 { + return ((a.x * b.y) - (a.y * b.x)); + } + + fn isCCW_15(aX: f32, aYSign: bool, bX: f32, bYSign: bool) -> bool { + let sameSide = (aYSign == bYSign); + return select(aYSign, (aYSign == (aX >= bX)), sameSide); + } + + const lookup_17: array = array(5u, 3u, 4u, 3u, 2u, 1u, 0u, 0u); + + fn rank3_16(aGb: bool, bGc: bool, aGc: bool) -> u32 { + let code = (((u32(aGb) << 2u) | (u32(bGc) << 1u)) | u32(aGc)); + return lookup_17[code]; + } + + fn joinSituationIndex_13(ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f) -> u32 { + let crossUL = cross2d_14(ur, ul); + let crossDL = cross2d_14(ur, dl); + let crossDR = cross2d_14(ur, dr); + let signUL = (crossUL >= 0f); + let signDL = (crossDL >= 0f); + let signDR = (crossDR >= 0f); + let dotUL = dot(ur, ul); + let dotDL = dot(ur, dl); + let dotDR = dot(ur, dr); + return rank3_16(isCCW_15(dotUL, signUL, dotDL, signDL), isCCW_15(dotDL, signDL, dotDR, signDR), isCCW_15(dotUL, signUL, dotDR, signDR)); + } + + const JOIN_LIMIT_18: f32 = 0.999f; + + fn rot90ccw_21(v: vec2f) -> vec2f { + return vec2f(-(v.y), v.x); + } + + fn rot90cw_22(v: vec2f) -> vec2f { + return vec2f(v.y, -(v.x)); + } + + fn bisectCcw_20(a: vec2f, b: vec2f) -> vec2f { + let sin = cross2d_14(a, b); + let sinSign = select(-1f, 1f, (sin >= 0f)); + var orthoA = rot90ccw_21(a); + var orthoB = rot90cw_22(b); + var dir = select(((a + b) * sinSign), (orthoA + orthoB), (dot(a, b) < 0f)); + return normalize(dir); + } + + fn midPoint_23(a: vec2f, b: vec2f) -> vec2f { + return (0.5 * (a + b)); + } + + fn addMul_24(a: vec2f, b: vec2f, f: f32) -> vec2f { + return (a + (b * f)); + } + + fn miterPoint_19(a: vec2f, b: vec2f) -> vec2f { + let sin_ = cross2d_14(a, b); + var bisection = bisectCcw_20(a, b); + let b2 = dot(b, b); + let cos_ = dot(a, b); + let diff = (b2 - cos_); + if (((diff * diff) < 1e-4f)) { + return midPoint_23(a, b); + } + if ((sin_ < 0f)) { + return (bisection * -1000000); + } + let t = (diff / sin_); + return addMul_24(a, rot90ccw_21(a), t); + } + + struct LimitAlongResult_26 { + a: vec2f, + b: vec2f, + limitWasHit: bool, + } + + fn limitTowardsMiddle_25(middle: vec2f, dir: vec2f, p1: vec2f, p2: vec2f) -> LimitAlongResult_26 { + let t1 = dot((p1 - middle), dir); + let t2 = dot((p2 - middle), dir); + if ((t1 <= t2)) { + return LimitAlongResult_26(p1, p2, false); + } + let t = clamp((t1 / (t1 - t2)), 0f, 1f); + var p = mix(p1, p2, t); + return LimitAlongResult_26(p, p, true); + } + + fn bisectNoCheck_28(a: vec2f, b: vec2f) -> vec2f { + return normalize((a + b)); + } + + fn item_27(vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, right: vec2f, dir: vec2f, left: vec2f) -> vec2f { + var uR = right; + var u = dir; + var c = dir; + var d = dir; + var dR = left; + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = bisectCcw_20(d0, d1); + var path = joinPath.path; + for (var depth = joinPath.depth; (depth > 0i); depth -= 1i) { + let isLeftChild = ((path & 1u) == 0u); + d0 = select(dm, d0, isLeftChild); + d1 = select(d1, dm, isLeftChild); + dm = bisectNoCheck_28(d0, d1); + path >>= 1u; + } + return addMul_24(V.position, dm, V.radius); + } + var v1 = addMul_24(V.position, u, V.radius); + var v2 = addMul_24(V.position, c, V.radius); + var v3 = addMul_24(V.position, d, V.radius); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + struct Intersection_31 { + valid: bool, + t: f32, + point: vec2f, + } + + fn intersectLines_30(A1: vec2f, A2: vec2f, B1: vec2f, B2: vec2f) -> Intersection_31 { + var a = (A2 - A1); + var b = (B2 - B1); + let axb = cross2d_14(a, b); + var AB = (B1 - A1); + let t = (cross2d_14(AB, b) / axb); + return Intersection_31((axb != 0f), t, addMul_24(A1, a, t)); + } + + fn item_29(situationIndex: u32, vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f, joinU: bool, joinD: bool) -> vec2f { + var midU = bisectCcw_20(ur, ul); + var midD = bisectCcw_20(dl, dr); + var midR = bisectCcw_20(ur, dr); + var midL = bisectCcw_20(dl, ul); + let shouldCross = ((situationIndex == 1u) || (situationIndex == 4u)); + var crossCenter = intersectLines_30(ul, dl, ur, dr).point; + var averageCenter = (((ur + ul) + (dl + dr)) * 0.25); + var uR = ur; + var u = midU; + var c = select(averageCenter, crossCenter, shouldCross); + var d = midD; + var dR = dr; + if ((situationIndex == 2u)) { + uR = ur; + u = midR; + c = midR; + d = midR; + dR = dr; + } + if ((situationIndex == 3u)) { + uR = ur; + u = midL; + c = midL; + d = midL; + dR = dr; + } + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = bisectCcw_20(d0, d1); + var path = joinPath.path; + for (var depth = joinPath.depth; (depth > 0i); depth -= 1i) { + let isLeftChild = ((path & 1u) == 0u); + d0 = select(dm, d0, isLeftChild); + d1 = select(d1, dm, isLeftChild); + dm = bisectNoCheck_28(d0, d1); + path >>= 1u; + } + return addMul_24(V.position, dm, V.radius); + } + var v1 = select(vu, addMul_24(V.position, u, V.radius), joinU); + var v2 = select(vu, addMul_24(V.position, c, V.radius), (joinU || joinD)); + var v3 = select(vd, addMul_24(V.position, d, V.radius), joinD); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn lineSegmentVariableWidth_6(vertexIndex: u32, A: LineSegmentVertex_4, B: LineSegmentVertex_4, C: LineSegmentVertex_4, D: LineSegmentVertex_4) -> LineSegmentOutput_10 { + var joinPath = getJoinVertexPath_7(vertexIndex); + var AB = (B.position - A.position); + var BC = (C.position - B.position); + var CD = (D.position - C.position); + let radiusABDelta = (A.radius - B.radius); + let radiusBCDelta = (B.radius - C.radius); + let radiusCDDelta = (C.radius - D.radius); + if ((dot(BC, BC) <= (radiusBCDelta * radiusBCDelta))) { + return LineSegmentOutput_10(vec2f(), 0u); + } + let isCapB = (dot(AB, AB) <= ((radiusABDelta * radiusABDelta) + 1e-12f)); + let isCapC = (dot(CD, CD) <= ((radiusCDDelta * radiusCDDelta) + 1e-12f)); + var eAB = externalNormals_11(AB, A.radius, B.radius); + var eBC = externalNormals_11(BC, B.radius, C.radius); + var eCD = externalNormals_11(CD, C.radius, D.radius); + var nBC = normalize(BC); + var nCB = (nBC * -1); + var d0 = eBC.n1; + var d4 = eBC.n2; + var d5 = eBC.n2; + var d9 = eBC.n1; + let situationIndexB = joinSituationIndex_13(eAB.n1, eBC.n1, eAB.n2, eBC.n2); + let situationIndexC = joinSituationIndex_13(eCD.n2, eBC.n2, eCD.n1, eBC.n1); + var joinBu = true; + var joinBd = true; + var joinCu = true; + var joinCd = true; + if (!isCapB) { + if ((((situationIndexB == 1u) || (situationIndexB == 5u)) || (dot(eBC.n2, eAB.n2) > JOIN_LIMIT_18))) { + d4 = miterPoint_19(eBC.n2, eAB.n2); + joinBd = false; + } + if ((((situationIndexB == 4u) || (situationIndexB == 5u)) || (dot(eAB.n1, eBC.n1) > JOIN_LIMIT_18))) { + d0 = miterPoint_19(eAB.n1, eBC.n1); + joinBu = false; + } + } + if (!isCapC) { + if ((((situationIndexC == 4u) || (situationIndexC == 5u)) || (dot(eCD.n2, eBC.n2) > JOIN_LIMIT_18))) { + d5 = miterPoint_19(eCD.n2, eBC.n2); + joinCd = false; + } + if ((((situationIndexC == 1u) || (situationIndexC == 5u)) || (dot(eBC.n1, eCD.n1) > JOIN_LIMIT_18))) { + d9 = miterPoint_19(eBC.n1, eCD.n1); + joinCu = false; + } + } + var v0 = addMul_24(B.position, d0, B.radius); + var v4 = addMul_24(B.position, d4, B.radius); + var v5 = addMul_24(C.position, d5, C.radius); + var v9 = addMul_24(C.position, d9, C.radius); + var midBC = midPoint_23(B.position, C.position); + var tBC1 = rot90cw_22(eBC.n1); + var tBC2 = rot90ccw_21(eBC.n2); + var limU = limitTowardsMiddle_25(midBC, tBC1, v0, v9); + var limD = limitTowardsMiddle_25(midBC, tBC2, v4, v5); + v0 = limU.a; + v9 = limU.b; + v4 = limD.a; + v5 = limD.b; + let isCSide = (joinPath.joinIndex >= 2u); + var situationIndex = situationIndexB; + var V = B; + var isCap = isCapB; + var j1 = eAB.n1; + var j2 = eBC.n1; + var j3 = eAB.n2; + var j4 = eBC.n2; + var vu = v0; + var vd = v4; + var joinU = joinBu; + var joinD = joinBd; + if (isCSide) { + situationIndex = situationIndexC; + V = C; + isCap = isCapC; + j4 = eBC.n1; + j3 = eCD.n1; + j2 = eBC.n2; + j1 = eCD.n2; + vu = v5; + vd = v9; + joinU = joinCd; + joinD = joinCu; + } + let joinIndex = joinPath.joinIndex; + if ((vertexIndex >= 10u)) { + var shouldJoin = array(u32(joinBu), u32(joinBd), u32(joinCd), u32(joinCu)); + if ((shouldJoin[joinIndex] == 0u)) { + var noJoinPoints = array(v0, v4, v5, v9); + let vertexPosition2 = (&noJoinPoints[joinIndex]); + return LineSegmentOutput_10((*vertexPosition2), situationIndex); + } + } + var vertexPosition = vec2f(); + if (isCap) { + if (isCSide) { + vertexPosition = item_27(vertexIndex, joinPath, V, vu, vd, j2, nBC, j4); + } + else { + vertexPosition = item_27(vertexIndex, joinPath, V, vu, vd, j2, nCB, j4); + } + } + else { + vertexPosition = item_29(situationIndex, vertexIndex, joinPath, V, vu, vd, j1, j2, j3, j4, joinU, joinD); + } + return LineSegmentOutput_10(vertexPosition, situationIndex); + } + + fn uvToLineSegment_32(A: vec2f, B: vec2f, point: vec2f) -> vec2f { + var p = (point - A); + var AB = (B - A); + let x = (dot(p, AB) / dot(AB, AB)); + let y = cross2d_14(normalize(AB), p); + return vec2f(x, y); + } + + struct mainVertex_Input_33 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn mainVertex_0(_arg_0: mainVertex_Input_33) -> mainVertex_Output_5 { + let t = uniforms_1.time; + var A = item_3(_arg_0.instanceIndex, t); + var B = item_3((_arg_0.instanceIndex + 1u), t); + var C = item_3((_arg_0.instanceIndex + 2u), t); + var D = item_3((_arg_0.instanceIndex + 3u), t); + if (((((A.radius < 0f) || (B.radius < 0f)) || (C.radius < 0f)) || (D.radius < 0f))) { + return mainVertex_Output_5(vec4f(), vec2f(), vec2f(), 0u, 0u, 0u); + } + var result = lineSegmentVariableWidth_6(_arg_0.vertexIndex, A, B, C, D); + var uv = uvToLineSegment_32(B.position, C.position, result.vertexPosition); + return mainVertex_Output_5(vec4f(result.vertexPosition, 0f, 1f), result.vertexPosition, uv, _arg_0.instanceIndex, _arg_0.vertexIndex, result.situationIndex); + } + + struct mainFragment_Input_35 { + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + @builtin(front_facing) frontFacing: bool, + @builtin(position) screenPosition: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + } + + @fragment fn mainFragment_34(_arg_0: mainFragment_Input_35) -> @location(0) vec4f { + let fillType2 = uniforms_1.fillType; + if ((fillType2 == 1u)) { + return mix(vec4f(0.7699999809265137, 0.38999998569488525, 1, 0.5), vec4f(0.10999999940395355, 0.4399999976158142, 0.9399999976158142, 0.5), ((_arg_0.position.x * 0.5f) + 0.5f)); + } + var color = vec3f(); + var colors = array(vec3f(1, 0, 0), vec3f(0, 1, 0), vec3f(0, 0, 1), vec3f(1, 0, 1), vec3f(1, 1, 0), vec3f(0, 1, 1), vec3f(0.75, 0.25, 0.25), vec3f(0.25, 0.75, 0.25), vec3f(0.25, 0.25, 0.75)); + if ((fillType2 == 2u)) { + color = colors[(_arg_0.instanceIndex % 9u)]; + } + if ((fillType2 == 3u)) { + color = colors[(_arg_0.vertexIndex % 9u)]; + } + if ((fillType2 == 4u)) { + color = colors[(_arg_0.situationIndex % 9u)]; + } + if ((fillType2 == 5u)) { + color = vec3f(_arg_0.uv.x, cos((_arg_0.uv.y * 100f)), 0f); + } + if (_arg_0.frontFacing) { + return vec4f(color, 0.5f); + } + return vec4f(color, select(0f, 1f, (((u32(_arg_0.screenPosition.x) >> 3u) % 2u) != ((u32(_arg_0.screenPosition.y) >> 3u) % 2u)))); + } + + struct Uniforms_2 { + time: f32, + fillType: u32, + } + + @group(0) @binding(0) var uniforms_1: Uniforms_2; + + struct LineSegmentVertex_4 { + position: vec2f, + radius: f32, + } + + fn item_3(vertexIndex: u32, time: f32) -> LineSegmentVertex_4 { + let s = sin(time); + let c = cos(time); + const r = 0.25; + var points = array(vec2f(((r * s) - 0.25f), (r * c)), vec2f(-0.25, 0), vec2f(0.25, 0), vec2f(((-(r) * s) + 0.25f), (r * c))); + let i = clamp((i32(vertexIndex) - 1i), 0i, 3i); + return LineSegmentVertex_4(points[i], 0.2f); + } + + struct mainVertex_Output_5 { + @builtin(position) outPos: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + } + + struct JoinPath_8 { + joinIndex: u32, + path: u32, + depth: i32, + } + + fn getJoinParent_9(i: u32) -> u32 { + return ((i - 4u) >> 1u); + } + + fn getJoinVertexPath_7(vertexIndex: u32) -> JoinPath_8 { + var lookup = array(0u, 0u, 0u, 1u, 1u, 2u, 2u, 2u, 3u, 3u); + if ((vertexIndex < 10u)) { + return JoinPath_8(lookup[vertexIndex], 0u, -1i); + } + var joinIndex = (vertexIndex - 10u); + var depth = 0; + var path = 0u; + while ((joinIndex >= 4u)) { + path = ((path << 1u) | (joinIndex & 1u)); + joinIndex = getJoinParent_9(joinIndex); + depth += 1i; + } + return JoinPath_8(joinIndex, path, depth); + } + + struct LineSegmentOutput_10 { + vertexPosition: vec2f, + situationIndex: u32, + } + + struct ExternalNormals_12 { + n1: vec2f, + n2: vec2f, + } + + fn externalNormals_11(distance: vec2f, r1: f32, r2: f32) -> ExternalNormals_12 { + var dNorm = normalize(distance); + let expCos = ((r1 - r2) / length(distance)); + let expSin = sqrt(max(0f, (1f - (expCos * expCos)))); + let a = (dNorm.x * expCos); + let b = (dNorm.y * expSin); + let c = (dNorm.x * expSin); + let d = (dNorm.y * expCos); + var n1 = vec2f((a - b), (c + d)); + var n2 = vec2f((a + b), (-(c) + d)); + return ExternalNormals_12(n1, n2); + } + + fn cross2d_14(a: vec2f, b: vec2f) -> f32 { + return ((a.x * b.y) - (a.y * b.x)); + } + + fn isCCW_15(aX: f32, aYSign: bool, bX: f32, bYSign: bool) -> bool { + let sameSide = (aYSign == bYSign); + return select(aYSign, (aYSign == (aX >= bX)), sameSide); + } + + const lookup_17: array = array(5u, 3u, 4u, 3u, 2u, 1u, 0u, 0u); + + fn rank3_16(aGb: bool, bGc: bool, aGc: bool) -> u32 { + let code = (((u32(aGb) << 2u) | (u32(bGc) << 1u)) | u32(aGc)); + return lookup_17[code]; + } + + fn joinSituationIndex_13(ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f) -> u32 { + let crossUL = cross2d_14(ur, ul); + let crossDL = cross2d_14(ur, dl); + let crossDR = cross2d_14(ur, dr); + let signUL = (crossUL >= 0f); + let signDL = (crossDL >= 0f); + let signDR = (crossDR >= 0f); + let dotUL = dot(ur, ul); + let dotDL = dot(ur, dl); + let dotDR = dot(ur, dr); + return rank3_16(isCCW_15(dotUL, signUL, dotDL, signDL), isCCW_15(dotDL, signDL, dotDR, signDR), isCCW_15(dotUL, signUL, dotDR, signDR)); + } + + const JOIN_LIMIT_18: f32 = 0.999f; + + fn rot90ccw_21(v: vec2f) -> vec2f { + return vec2f(-(v.y), v.x); + } + + fn rot90cw_22(v: vec2f) -> vec2f { + return vec2f(v.y, -(v.x)); + } + + fn bisectCcw_20(a: vec2f, b: vec2f) -> vec2f { + let sin = cross2d_14(a, b); + let sinSign = select(-1f, 1f, (sin >= 0f)); + var orthoA = rot90ccw_21(a); + var orthoB = rot90cw_22(b); + var dir = select(((a + b) * sinSign), (orthoA + orthoB), (dot(a, b) < 0f)); + return normalize(dir); + } + + fn midPoint_23(a: vec2f, b: vec2f) -> vec2f { + return (0.5 * (a + b)); + } + + fn addMul_24(a: vec2f, b: vec2f, f: f32) -> vec2f { + return (a + (b * f)); + } + + fn miterPoint_19(a: vec2f, b: vec2f) -> vec2f { + let sin_ = cross2d_14(a, b); + var bisection = bisectCcw_20(a, b); + let b2 = dot(b, b); + let cos_ = dot(a, b); + let diff = (b2 - cos_); + if (((diff * diff) < 1e-4f)) { + return midPoint_23(a, b); + } + if ((sin_ < 0f)) { + return (bisection * -1000000); + } + let t = (diff / sin_); + return addMul_24(a, rot90ccw_21(a), t); + } + + struct LimitAlongResult_26 { + a: vec2f, + b: vec2f, + limitWasHit: bool, + } + + fn limitTowardsMiddle_25(middle: vec2f, dir: vec2f, p1: vec2f, p2: vec2f) -> LimitAlongResult_26 { + let t1 = dot((p1 - middle), dir); + let t2 = dot((p2 - middle), dir); + if ((t1 <= t2)) { + return LimitAlongResult_26(p1, p2, false); + } + let t = clamp((t1 / (t1 - t2)), 0f, 1f); + var p = mix(p1, p2, t); + return LimitAlongResult_26(p, p, true); + } + + fn bisectNoCheck_28(a: vec2f, b: vec2f) -> vec2f { + return normalize((a + b)); + } + + fn item_27(vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, right: vec2f, dir: vec2f, left: vec2f) -> vec2f { + var uR = right; + var u = dir; + var c = dir; + var d = dir; + var dR = left; + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = bisectCcw_20(d0, d1); + var path = joinPath.path; + for (var depth = joinPath.depth; (depth > 0i); depth -= 1i) { + let isLeftChild = ((path & 1u) == 0u); + d0 = select(dm, d0, isLeftChild); + d1 = select(d1, dm, isLeftChild); + dm = bisectNoCheck_28(d0, d1); + path >>= 1u; + } + return addMul_24(V.position, dm, V.radius); + } + var v1 = addMul_24(V.position, u, V.radius); + var v2 = addMul_24(V.position, c, V.radius); + var v3 = addMul_24(V.position, d, V.radius); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + struct Intersection_31 { + valid: bool, + t: f32, + point: vec2f, + } + + fn intersectLines_30(A1: vec2f, A2: vec2f, B1: vec2f, B2: vec2f) -> Intersection_31 { + var a = (A2 - A1); + var b = (B2 - B1); + let axb = cross2d_14(a, b); + var AB = (B1 - A1); + let t = (cross2d_14(AB, b) / axb); + return Intersection_31((axb != 0f), t, addMul_24(A1, a, t)); + } + + fn item_29(situationIndex: u32, vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f, joinU: bool, joinD: bool) -> vec2f { + var midU = bisectCcw_20(ur, ul); + var midD = bisectCcw_20(dl, dr); + var midR = bisectCcw_20(ur, dr); + var midL = bisectCcw_20(dl, ul); + let shouldCross = ((situationIndex == 1u) || (situationIndex == 4u)); + var crossCenter = intersectLines_30(ul, dl, ur, dr).point; + var averageCenter = (((ur + ul) + (dl + dr)) * 0.25); + var uR = ur; + var u = midU; + var c = select(averageCenter, crossCenter, shouldCross); + var d = midD; + var dR = dr; + if ((situationIndex == 2u)) { + uR = ur; + u = midR; + c = midR; + d = midR; + dR = dr; + } + if ((situationIndex == 3u)) { + uR = ur; + u = midL; + c = midL; + d = midL; + dR = dr; + } + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = bisectCcw_20(d0, d1); + var path = joinPath.path; + for (var depth = joinPath.depth; (depth > 0i); depth -= 1i) { + let isLeftChild = ((path & 1u) == 0u); + d0 = select(dm, d0, isLeftChild); + d1 = select(d1, dm, isLeftChild); + dm = bisectNoCheck_28(d0, d1); + path >>= 1u; + } + return addMul_24(V.position, dm, V.radius); + } + var v1 = select(vu, addMul_24(V.position, u, V.radius), joinU); + var v2 = select(vu, addMul_24(V.position, c, V.radius), (joinU || joinD)); + var v3 = select(vd, addMul_24(V.position, d, V.radius), joinD); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn lineSegmentVariableWidth_6(vertexIndex: u32, A: LineSegmentVertex_4, B: LineSegmentVertex_4, C: LineSegmentVertex_4, D: LineSegmentVertex_4) -> LineSegmentOutput_10 { + var joinPath = getJoinVertexPath_7(vertexIndex); + var AB = (B.position - A.position); + var BC = (C.position - B.position); + var CD = (D.position - C.position); + let radiusABDelta = (A.radius - B.radius); + let radiusBCDelta = (B.radius - C.radius); + let radiusCDDelta = (C.radius - D.radius); + if ((dot(BC, BC) <= (radiusBCDelta * radiusBCDelta))) { + return LineSegmentOutput_10(vec2f(), 0u); + } + let isCapB = (dot(AB, AB) <= ((radiusABDelta * radiusABDelta) + 1e-12f)); + let isCapC = (dot(CD, CD) <= ((radiusCDDelta * radiusCDDelta) + 1e-12f)); + var eAB = externalNormals_11(AB, A.radius, B.radius); + var eBC = externalNormals_11(BC, B.radius, C.radius); + var eCD = externalNormals_11(CD, C.radius, D.radius); + var nBC = normalize(BC); + var nCB = (nBC * -1); + var d0 = eBC.n1; + var d4 = eBC.n2; + var d5 = eBC.n2; + var d9 = eBC.n1; + let situationIndexB = joinSituationIndex_13(eAB.n1, eBC.n1, eAB.n2, eBC.n2); + let situationIndexC = joinSituationIndex_13(eCD.n2, eBC.n2, eCD.n1, eBC.n1); + var joinBu = true; + var joinBd = true; + var joinCu = true; + var joinCd = true; + if (!isCapB) { + if ((((situationIndexB == 1u) || (situationIndexB == 5u)) || (dot(eBC.n2, eAB.n2) > JOIN_LIMIT_18))) { + d4 = miterPoint_19(eBC.n2, eAB.n2); + joinBd = false; + } + if ((((situationIndexB == 4u) || (situationIndexB == 5u)) || (dot(eAB.n1, eBC.n1) > JOIN_LIMIT_18))) { + d0 = miterPoint_19(eAB.n1, eBC.n1); + joinBu = false; + } + } + if (!isCapC) { + if ((((situationIndexC == 4u) || (situationIndexC == 5u)) || (dot(eCD.n2, eBC.n2) > JOIN_LIMIT_18))) { + d5 = miterPoint_19(eCD.n2, eBC.n2); + joinCd = false; + } + if ((((situationIndexC == 1u) || (situationIndexC == 5u)) || (dot(eBC.n1, eCD.n1) > JOIN_LIMIT_18))) { + d9 = miterPoint_19(eBC.n1, eCD.n1); + joinCu = false; + } + } + var v0 = addMul_24(B.position, d0, B.radius); + var v4 = addMul_24(B.position, d4, B.radius); + var v5 = addMul_24(C.position, d5, C.radius); + var v9 = addMul_24(C.position, d9, C.radius); + var midBC = midPoint_23(B.position, C.position); + var tBC1 = rot90cw_22(eBC.n1); + var tBC2 = rot90ccw_21(eBC.n2); + var limU = limitTowardsMiddle_25(midBC, tBC1, v0, v9); + var limD = limitTowardsMiddle_25(midBC, tBC2, v4, v5); + v0 = limU.a; + v9 = limU.b; + v4 = limD.a; + v5 = limD.b; + let isCSide = (joinPath.joinIndex >= 2u); + var situationIndex = situationIndexB; + var V = B; + var isCap = isCapB; + var j1 = eAB.n1; + var j2 = eBC.n1; + var j3 = eAB.n2; + var j4 = eBC.n2; + var vu = v0; + var vd = v4; + var joinU = joinBu; + var joinD = joinBd; + if (isCSide) { + situationIndex = situationIndexC; + V = C; + isCap = isCapC; + j4 = eBC.n1; + j3 = eCD.n1; + j2 = eBC.n2; + j1 = eCD.n2; + vu = v5; + vd = v9; + joinU = joinCd; + joinD = joinCu; + } + let joinIndex = joinPath.joinIndex; + if ((vertexIndex >= 10u)) { + var shouldJoin = array(u32(joinBu), u32(joinBd), u32(joinCd), u32(joinCu)); + if ((shouldJoin[joinIndex] == 0u)) { + var noJoinPoints = array(v0, v4, v5, v9); + let vertexPosition2 = (&noJoinPoints[joinIndex]); + return LineSegmentOutput_10((*vertexPosition2), situationIndex); + } + } + var vertexPosition = vec2f(); + if (isCap) { + if (isCSide) { + vertexPosition = item_27(vertexIndex, joinPath, V, vu, vd, j2, nBC, j4); + } + else { + vertexPosition = item_27(vertexIndex, joinPath, V, vu, vd, j2, nCB, j4); + } + } + else { + vertexPosition = item_29(situationIndex, vertexIndex, joinPath, V, vu, vd, j1, j2, j3, j4, joinU, joinD); + } + return LineSegmentOutput_10(vertexPosition, situationIndex); + } + + fn uvToLineSegment_32(A: vec2f, B: vec2f, point: vec2f) -> vec2f { + var p = (point - A); + var AB = (B - A); + let x = (dot(p, AB) / dot(AB, AB)); + let y = cross2d_14(normalize(AB), p); + return vec2f(x, y); + } + + struct mainVertex_Input_33 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn mainVertex_0(_arg_0: mainVertex_Input_33) -> mainVertex_Output_5 { + let t = uniforms_1.time; + var A = item_3(_arg_0.instanceIndex, t); + var B = item_3((_arg_0.instanceIndex + 1u), t); + var C = item_3((_arg_0.instanceIndex + 2u), t); + var D = item_3((_arg_0.instanceIndex + 3u), t); + if (((((A.radius < 0f) || (B.radius < 0f)) || (C.radius < 0f)) || (D.radius < 0f))) { + return mainVertex_Output_5(vec4f(), vec2f(), vec2f(), 0u, 0u, 0u); + } + var result = lineSegmentVariableWidth_6(_arg_0.vertexIndex, A, B, C, D); + var uv = uvToLineSegment_32(B.position, C.position, result.vertexPosition); + return mainVertex_Output_5(vec4f(result.vertexPosition, 0f, 1f), result.vertexPosition, uv, _arg_0.instanceIndex, _arg_0.vertexIndex, result.situationIndex); + } + + struct outlineFragment_Input_35 { + @builtin(front_facing) _unused: bool, + } + + @fragment fn outlineFragment_34(_arg_0: outlineFragment_Input_35) -> @location(0) vec4f { + return vec4f(0, 0, 0, 0.20000000298023224); + } + + struct Uniforms_2 { + time: f32, + fillType: u32, + } + + @group(0) @binding(0) var uniforms_1: Uniforms_2; + + struct LineSegmentVertex_4 { + position: vec2f, + radius: f32, + } + + fn item_3(vertexIndex: u32, time: f32) -> LineSegmentVertex_4 { + let i = ((f32(vertexIndex) % 2000f) / 2000f); + let x = cos(((25.132741228718345f * i) + 1.5707963267948966f)); + let y = cos((31.41592653589793f * i)); + return LineSegmentVertex_4(vec2f((0.8f * x), (0.8f * y)), (0.05f * clamp(sin(((25.132741228718345f * i) - (3f * time))), 0.1f, 1f))); + } + + struct mainVertex_Output_5 { + @builtin(position) outPos: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + } + + struct JoinPath_8 { + joinIndex: u32, + path: u32, + depth: i32, + } + + fn getJoinParent_9(i: u32) -> u32 { + return ((i - 4u) >> 1u); + } + + fn getJoinVertexPath_7(vertexIndex: u32) -> JoinPath_8 { + var lookup = array(0u, 0u, 0u, 1u, 1u, 2u, 2u, 2u, 3u, 3u); + if ((vertexIndex < 10u)) { + return JoinPath_8(lookup[vertexIndex], 0u, -1i); + } + var joinIndex = (vertexIndex - 10u); + var depth = 0; + var path = 0u; + while ((joinIndex >= 4u)) { + path = ((path << 1u) | (joinIndex & 1u)); + joinIndex = getJoinParent_9(joinIndex); + depth += 1i; + } + return JoinPath_8(joinIndex, path, depth); + } + + struct LineSegmentOutput_10 { + vertexPosition: vec2f, + situationIndex: u32, + } + + struct ExternalNormals_12 { + n1: vec2f, + n2: vec2f, + } + + fn externalNormals_11(distance: vec2f, r1: f32, r2: f32) -> ExternalNormals_12 { + var dNorm = normalize(distance); + let expCos = ((r1 - r2) / length(distance)); + let expSin = sqrt(max(0f, (1f - (expCos * expCos)))); + let a = (dNorm.x * expCos); + let b = (dNorm.y * expSin); + let c = (dNorm.x * expSin); + let d = (dNorm.y * expCos); + var n1 = vec2f((a - b), (c + d)); + var n2 = vec2f((a + b), (-(c) + d)); + return ExternalNormals_12(n1, n2); + } + + fn cross2d_14(a: vec2f, b: vec2f) -> f32 { + return ((a.x * b.y) - (a.y * b.x)); + } + + fn isCCW_15(aX: f32, aYSign: bool, bX: f32, bYSign: bool) -> bool { + let sameSide = (aYSign == bYSign); + return select(aYSign, (aYSign == (aX >= bX)), sameSide); + } + + const lookup_17: array = array(5u, 3u, 4u, 3u, 2u, 1u, 0u, 0u); + + fn rank3_16(aGb: bool, bGc: bool, aGc: bool) -> u32 { + let code = (((u32(aGb) << 2u) | (u32(bGc) << 1u)) | u32(aGc)); + return lookup_17[code]; + } + + fn joinSituationIndex_13(ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f) -> u32 { + let crossUL = cross2d_14(ur, ul); + let crossDL = cross2d_14(ur, dl); + let crossDR = cross2d_14(ur, dr); + let signUL = (crossUL >= 0f); + let signDL = (crossDL >= 0f); + let signDR = (crossDR >= 0f); + let dotUL = dot(ur, ul); + let dotDL = dot(ur, dl); + let dotDR = dot(ur, dr); + return rank3_16(isCCW_15(dotUL, signUL, dotDL, signDL), isCCW_15(dotDL, signDL, dotDR, signDR), isCCW_15(dotUL, signUL, dotDR, signDR)); + } + + const JOIN_LIMIT_18: f32 = 0.999f; + + fn rot90ccw_21(v: vec2f) -> vec2f { + return vec2f(-(v.y), v.x); + } + + fn rot90cw_22(v: vec2f) -> vec2f { + return vec2f(v.y, -(v.x)); + } + + fn bisectCcw_20(a: vec2f, b: vec2f) -> vec2f { + let sin = cross2d_14(a, b); + let sinSign = select(-1f, 1f, (sin >= 0f)); + var orthoA = rot90ccw_21(a); + var orthoB = rot90cw_22(b); + var dir = select(((a + b) * sinSign), (orthoA + orthoB), (dot(a, b) < 0f)); + return normalize(dir); + } + + fn midPoint_23(a: vec2f, b: vec2f) -> vec2f { + return (0.5 * (a + b)); + } + + fn addMul_24(a: vec2f, b: vec2f, f: f32) -> vec2f { + return (a + (b * f)); + } + + fn miterPoint_19(a: vec2f, b: vec2f) -> vec2f { + let sin_ = cross2d_14(a, b); + var bisection = bisectCcw_20(a, b); + let b2 = dot(b, b); + let cos_ = dot(a, b); + let diff = (b2 - cos_); + if (((diff * diff) < 1e-4f)) { + return midPoint_23(a, b); + } + if ((sin_ < 0f)) { + return (bisection * -1000000); + } + let t = (diff / sin_); + return addMul_24(a, rot90ccw_21(a), t); + } + + struct LimitAlongResult_26 { + a: vec2f, + b: vec2f, + limitWasHit: bool, + } + + fn limitTowardsMiddle_25(middle: vec2f, dir: vec2f, p1: vec2f, p2: vec2f) -> LimitAlongResult_26 { + let t1 = dot((p1 - middle), dir); + let t2 = dot((p2 - middle), dir); + if ((t1 <= t2)) { + return LimitAlongResult_26(p1, p2, false); + } + let t = clamp((t1 / (t1 - t2)), 0f, 1f); + var p = mix(p1, p2, t); + return LimitAlongResult_26(p, p, true); + } + + fn item_27(vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, right: vec2f, dir: vec2f, left: vec2f) -> vec2f { + if ((joinPath.depth >= 0i)) { + var remove = array(right, left); + var dm = remove[(joinPath.joinIndex & 1u)]; + return addMul_24(V.position, dm, V.radius); + } + var v1 = addMul_24(V.position, right, V.radius); + var v2 = addMul_24(V.position, dir, V.radius); + var v3 = addMul_24(V.position, left, V.radius); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn intersectTangent_29(a: vec2f, n: vec2f) -> vec2f { + let cos_ = dot(a, n); + return (n * (1f / cos_)); + } + + fn miterPointNoCheck_30(a: vec2f, b: vec2f) -> vec2f { + var ab = (a + b); + return (ab * (2f / dot(ab, ab))); + } + + fn item_28(vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, right: vec2f, dir: vec2f, left: vec2f) -> vec2f { + let shouldJoin = (dot(dir, right) < 0f); + var dirRight = rot90cw_22(dir); + var dirLeft = rot90ccw_21(dir); + var u = select(intersectTangent_29(right, dirRight), dirRight, shouldJoin); + var c = vec2f(); + var d = select(intersectTangent_29(left, dirLeft), dirLeft, shouldJoin); + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var miterR = select(u, miterPointNoCheck_30(right, dirRight), shouldJoin); + var miterL = select(d, miterPointNoCheck_30(dirLeft, left), shouldJoin); + var parents = array(miterR, miterL); + let dm = (&parents[(joinIndex & 1u)]); + return addMul_24(V.position, (*dm), V.radius); + } + var v1 = addMul_24(V.position, u, V.radius); + var v0 = select(v1, vu, shouldJoin); + var v2 = addMul_24(V.position, c, V.radius); + var v3 = addMul_24(V.position, d, V.radius); + var v4 = select(v3, vd, shouldJoin); + var points = array(v0, v1, v2, v3, v4); + return points[(vertexIndex % 5u)]; + } + + fn miterLimit_32(miter: vec2f, limitRatio: f32) -> vec2f { + let m2 = dot(miter, miter); + if ((m2 > (limitRatio * limitRatio))) { + return (normalize(miter) * ((((limitRatio - 1f) * ((limitRatio * limitRatio) - 1f)) / (m2 - 1f)) + 1f)); + } + return miter; + } + + struct Intersection_34 { + valid: bool, + t: f32, + point: vec2f, + } + + fn intersectLines_33(A1: vec2f, A2: vec2f, B1: vec2f, B2: vec2f) -> Intersection_34 { + var a = (A2 - A1); + var b = (B2 - B1); + let axb = cross2d_14(a, b); + var AB = (B1 - A1); + let t = (cross2d_14(AB, b) / axb); + return Intersection_34((axb != 0f), t, addMul_24(A1, a, t)); + } + + fn item_31(situationIndex: u32, vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f, joinU: bool, joinD: bool) -> vec2f { + var miterU = miterPoint_19(ur, ul); + var miterD = miterPoint_19(dl, dr); + miterU = miterLimit_32(miterU, 2f); + miterD = miterLimit_32(miterD, 2f); + let shouldCross = ((situationIndex == 1u) || (situationIndex == 4u)); + var crossCenter = intersectLines_33(ul, dl, ur, dr).point; + var averageCenter = ((normalize(miterU) + normalize(miterD)) * 0.5); + var uR = ur; + var u = miterU; + var c = select(averageCenter, crossCenter, shouldCross); + var d = miterD; + var dR = dr; + if ((situationIndex == 2u)) { + var mid = bisectCcw_20(ur, dr); + uR = ur; + u = mid; + c = mid; + d = mid; + dR = dr; + } + if ((situationIndex == 3u)) { + var mid = bisectCcw_20(dl, ul); + uR = ur; + u = mid; + c = mid; + d = mid; + dR = dr; + } + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = miterPoint_19(d0, d1); + return addMul_24(V.position, dm, V.radius); + } + var v1 = select(vu, addMul_24(V.position, u, V.radius), joinU); + var v2 = select(vu, addMul_24(V.position, c, V.radius), (joinU || joinD)); + var v3 = select(vd, addMul_24(V.position, d, V.radius), joinD); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn lineSegmentVariableWidth_6(vertexIndex: u32, A: LineSegmentVertex_4, B: LineSegmentVertex_4, C: LineSegmentVertex_4, D: LineSegmentVertex_4) -> LineSegmentOutput_10 { + var joinPath = getJoinVertexPath_7(vertexIndex); + var AB = (B.position - A.position); + var BC = (C.position - B.position); + var CD = (D.position - C.position); + let radiusABDelta = (A.radius - B.radius); + let radiusBCDelta = (B.radius - C.radius); + let radiusCDDelta = (C.radius - D.radius); + if ((dot(BC, BC) <= (radiusBCDelta * radiusBCDelta))) { + return LineSegmentOutput_10(vec2f(), 0u); + } + let isCapB = (dot(AB, AB) <= ((radiusABDelta * radiusABDelta) + 1e-12f)); + let isCapC = (dot(CD, CD) <= ((radiusCDDelta * radiusCDDelta) + 1e-12f)); + var eAB = externalNormals_11(AB, A.radius, B.radius); + var eBC = externalNormals_11(BC, B.radius, C.radius); + var eCD = externalNormals_11(CD, C.radius, D.radius); + var nBC = normalize(BC); + var nCB = (nBC * -1); + var d0 = eBC.n1; + var d4 = eBC.n2; + var d5 = eBC.n2; + var d9 = eBC.n1; + let situationIndexB = joinSituationIndex_13(eAB.n1, eBC.n1, eAB.n2, eBC.n2); + let situationIndexC = joinSituationIndex_13(eCD.n2, eBC.n2, eCD.n1, eBC.n1); + var joinBu = true; + var joinBd = true; + var joinCu = true; + var joinCd = true; + if (!isCapB) { + if ((((situationIndexB == 1u) || (situationIndexB == 5u)) || (dot(eBC.n2, eAB.n2) > JOIN_LIMIT_18))) { + d4 = miterPoint_19(eBC.n2, eAB.n2); + joinBd = false; + } + if ((((situationIndexB == 4u) || (situationIndexB == 5u)) || (dot(eAB.n1, eBC.n1) > JOIN_LIMIT_18))) { + d0 = miterPoint_19(eAB.n1, eBC.n1); + joinBu = false; + } + } + if (!isCapC) { + if ((((situationIndexC == 4u) || (situationIndexC == 5u)) || (dot(eCD.n2, eBC.n2) > JOIN_LIMIT_18))) { + d5 = miterPoint_19(eCD.n2, eBC.n2); + joinCd = false; + } + if ((((situationIndexC == 1u) || (situationIndexC == 5u)) || (dot(eBC.n1, eCD.n1) > JOIN_LIMIT_18))) { + d9 = miterPoint_19(eBC.n1, eCD.n1); + joinCu = false; + } + } + var v0 = addMul_24(B.position, d0, B.radius); + var v4 = addMul_24(B.position, d4, B.radius); + var v5 = addMul_24(C.position, d5, C.radius); + var v9 = addMul_24(C.position, d9, C.radius); + var midBC = midPoint_23(B.position, C.position); + var tBC1 = rot90cw_22(eBC.n1); + var tBC2 = rot90ccw_21(eBC.n2); + var limU = limitTowardsMiddle_25(midBC, tBC1, v0, v9); + var limD = limitTowardsMiddle_25(midBC, tBC2, v4, v5); + v0 = limU.a; + v9 = limU.b; + v4 = limD.a; + v5 = limD.b; + let isCSide = (joinPath.joinIndex >= 2u); + var situationIndex = situationIndexB; + var V = B; + var isCap = isCapB; + var j1 = eAB.n1; + var j2 = eBC.n1; + var j3 = eAB.n2; + var j4 = eBC.n2; + var vu = v0; + var vd = v4; + var joinU = joinBu; + var joinD = joinBd; + if (isCSide) { + situationIndex = situationIndexC; + V = C; + isCap = isCapC; + j4 = eBC.n1; + j3 = eCD.n1; + j2 = eBC.n2; + j1 = eCD.n2; + vu = v5; + vd = v9; + joinU = joinCd; + joinD = joinCu; + } + let joinIndex = joinPath.joinIndex; + if ((vertexIndex >= 10u)) { + var shouldJoin = array(u32(joinBu), u32(joinBd), u32(joinCd), u32(joinCu)); + if ((shouldJoin[joinIndex] == 0u)) { + var noJoinPoints = array(v0, v4, v5, v9); + let vertexPosition2 = (&noJoinPoints[joinIndex]); + return LineSegmentOutput_10((*vertexPosition2), situationIndex); + } + } + var vertexPosition = vec2f(); + if (isCap) { + if (isCSide) { + vertexPosition = item_27(vertexIndex, joinPath, V, vu, vd, j2, nBC, j4); + } + else { + vertexPosition = item_28(vertexIndex, joinPath, V, vu, vd, j2, nCB, j4); + } + } + else { + vertexPosition = item_31(situationIndex, vertexIndex, joinPath, V, vu, vd, j1, j2, j3, j4, joinU, joinD); + } + return LineSegmentOutput_10(vertexPosition, situationIndex); + } + + fn uvToLineSegment_35(A: vec2f, B: vec2f, point: vec2f) -> vec2f { + var p = (point - A); + var AB = (B - A); + let x = (dot(p, AB) / dot(AB, AB)); + let y = cross2d_14(normalize(AB), p); + return vec2f(x, y); + } + + struct mainVertex_Input_36 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn mainVertex_0(_arg_0: mainVertex_Input_36) -> mainVertex_Output_5 { + let t = uniforms_1.time; + var A = item_3(_arg_0.instanceIndex, t); + var B = item_3((_arg_0.instanceIndex + 1u), t); + var C = item_3((_arg_0.instanceIndex + 2u), t); + var D = item_3((_arg_0.instanceIndex + 3u), t); + if (((((A.radius < 0f) || (B.radius < 0f)) || (C.radius < 0f)) || (D.radius < 0f))) { + return mainVertex_Output_5(vec4f(), vec2f(), vec2f(), 0u, 0u, 0u); + } + var result = lineSegmentVariableWidth_6(_arg_0.vertexIndex, A, B, C, D); + var uv = uvToLineSegment_35(B.position, C.position, result.vertexPosition); + return mainVertex_Output_5(vec4f(result.vertexPosition, 0f, 1f), result.vertexPosition, uv, _arg_0.instanceIndex, _arg_0.vertexIndex, result.situationIndex); + } + + struct mainFragment_Input_38 { + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + @builtin(front_facing) frontFacing: bool, + @builtin(position) screenPosition: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + } + + @fragment fn mainFragment_37(_arg_0: mainFragment_Input_38) -> @location(0) vec4f { + let fillType2 = uniforms_1.fillType; + if ((fillType2 == 1u)) { + return mix(vec4f(0.7699999809265137, 0.38999998569488525, 1, 0.5), vec4f(0.10999999940395355, 0.4399999976158142, 0.9399999976158142, 0.5), ((_arg_0.position.x * 0.5f) + 0.5f)); + } + var color = vec3f(); + var colors = array(vec3f(1, 0, 0), vec3f(0, 1, 0), vec3f(0, 0, 1), vec3f(1, 0, 1), vec3f(1, 1, 0), vec3f(0, 1, 1), vec3f(0.75, 0.25, 0.25), vec3f(0.25, 0.75, 0.25), vec3f(0.25, 0.25, 0.75)); + if ((fillType2 == 2u)) { + color = colors[(_arg_0.instanceIndex % 9u)]; + } + if ((fillType2 == 3u)) { + color = colors[(_arg_0.vertexIndex % 9u)]; + } + if ((fillType2 == 4u)) { + color = colors[(_arg_0.situationIndex % 9u)]; + } + if ((fillType2 == 5u)) { + color = vec3f(_arg_0.uv.x, cos((_arg_0.uv.y * 100f)), 0f); + } + if (_arg_0.frontFacing) { + return vec4f(color, 0.5f); + } + return vec4f(color, select(0f, 1f, (((u32(_arg_0.screenPosition.x) >> 3u) % 2u) != ((u32(_arg_0.screenPosition.y) >> 3u) % 2u)))); + } + + struct outlineFragment_Input_40 { + @builtin(front_facing) _unused: bool, + } + + @fragment fn outlineFragment_39(_arg_0: outlineFragment_Input_40) -> @location(0) vec4f { + return vec4f(0, 0, 0, 0.20000000298023224); + } + + struct centerlineVertex_Output_42 { + @builtin(position) outPos: vec4f, + } + + struct centerlineVertex_Input_43 { + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn centerlineVertex_41(_arg_0: centerlineVertex_Input_43) -> centerlineVertex_Output_42 { + let t = uniforms_1.time; + var vertex = item_3(_arg_0.vertexIndex, t); + if ((vertex.radius < 0f)) { + return centerlineVertex_Output_42(vec4f()); + } + return centerlineVertex_Output_42(vec4f(vertex.position, 0f, 1f)); + } + + struct circlesVertex_Output_45 { + @builtin(position) outPos: vec4f, + } + + struct circlesVertex_Input_46 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn circlesVertex_44(_arg_0: circlesVertex_Input_46) -> circlesVertex_Output_45 { + let t = uniforms_1.time; + var vertex = item_3(_arg_0.instanceIndex, t); + if ((vertex.radius < 0f)) { + return circlesVertex_Output_45(vec4f()); + } + let step = clamp((0.007853981633974483f / vertex.radius), 0.02454369260617026f, 0.39269908169872414f); + let angle = min(6.283185307179586f, (step * f32(_arg_0.vertexIndex))); + var unit = vec2f(cos(angle), sin(angle)); + return circlesVertex_Output_45(vec4f(addMul_24(vertex.position, unit, vertex.radius), 0f, 1f)); + } + + struct Uniforms_2 { + time: f32, + fillType: u32, + } + + @group(0) @binding(0) var uniforms_1: Uniforms_2; + + struct LineSegmentVertex_4 { + position: vec2f, + radius: f32, + } + + fn item_3(vertexIndex: u32, time: f32) -> LineSegmentVertex_4 { + let i = (clamp((f32(vertexIndex) - 1f), 0f, 48f) / 48f); + let x = ((2f * i) - 1f); + let s = sin(time); + let n = (((((10f * s) * s) * s) * s) + 0.25f); + let base = clamp((1f - pow(abs(x), n)), 0f, 1f); + return LineSegmentVertex_4(vec2f((0.5f * x), (0.5f * pow(base, (1f / n)))), 0.2f); + } + + struct mainVertex_Output_5 { + @builtin(position) outPos: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + } + + struct JoinPath_8 { + joinIndex: u32, + path: u32, + depth: i32, + } + + fn getJoinParent_9(i: u32) -> u32 { + return ((i - 4u) >> 1u); + } + + fn getJoinVertexPath_7(vertexIndex: u32) -> JoinPath_8 { + var lookup = array(0u, 0u, 0u, 1u, 1u, 2u, 2u, 2u, 3u, 3u); + if ((vertexIndex < 10u)) { + return JoinPath_8(lookup[vertexIndex], 0u, -1i); + } + var joinIndex = (vertexIndex - 10u); + var depth = 0; + var path = 0u; + while ((joinIndex >= 4u)) { + path = ((path << 1u) | (joinIndex & 1u)); + joinIndex = getJoinParent_9(joinIndex); + depth += 1i; + } + return JoinPath_8(joinIndex, path, depth); + } + + struct LineSegmentOutput_10 { + vertexPosition: vec2f, + situationIndex: u32, + } + + struct ExternalNormals_12 { + n1: vec2f, + n2: vec2f, + } + + fn externalNormals_11(distance: vec2f, r1: f32, r2: f32) -> ExternalNormals_12 { + var dNorm = normalize(distance); + let expCos = ((r1 - r2) / length(distance)); + let expSin = sqrt(max(0f, (1f - (expCos * expCos)))); + let a = (dNorm.x * expCos); + let b = (dNorm.y * expSin); + let c = (dNorm.x * expSin); + let d = (dNorm.y * expCos); + var n1 = vec2f((a - b), (c + d)); + var n2 = vec2f((a + b), (-(c) + d)); + return ExternalNormals_12(n1, n2); + } + + fn cross2d_14(a: vec2f, b: vec2f) -> f32 { + return ((a.x * b.y) - (a.y * b.x)); + } + + fn isCCW_15(aX: f32, aYSign: bool, bX: f32, bYSign: bool) -> bool { + let sameSide = (aYSign == bYSign); + return select(aYSign, (aYSign == (aX >= bX)), sameSide); + } + + const lookup_17: array = array(5u, 3u, 4u, 3u, 2u, 1u, 0u, 0u); + + fn rank3_16(aGb: bool, bGc: bool, aGc: bool) -> u32 { + let code = (((u32(aGb) << 2u) | (u32(bGc) << 1u)) | u32(aGc)); + return lookup_17[code]; + } + + fn joinSituationIndex_13(ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f) -> u32 { + let crossUL = cross2d_14(ur, ul); + let crossDL = cross2d_14(ur, dl); + let crossDR = cross2d_14(ur, dr); + let signUL = (crossUL >= 0f); + let signDL = (crossDL >= 0f); + let signDR = (crossDR >= 0f); + let dotUL = dot(ur, ul); + let dotDL = dot(ur, dl); + let dotDR = dot(ur, dr); + return rank3_16(isCCW_15(dotUL, signUL, dotDL, signDL), isCCW_15(dotDL, signDL, dotDR, signDR), isCCW_15(dotUL, signUL, dotDR, signDR)); + } + + const JOIN_LIMIT_18: f32 = 0.999f; + + fn rot90ccw_21(v: vec2f) -> vec2f { + return vec2f(-(v.y), v.x); + } + + fn rot90cw_22(v: vec2f) -> vec2f { + return vec2f(v.y, -(v.x)); + } + + fn bisectCcw_20(a: vec2f, b: vec2f) -> vec2f { + let sin = cross2d_14(a, b); + let sinSign = select(-1f, 1f, (sin >= 0f)); + var orthoA = rot90ccw_21(a); + var orthoB = rot90cw_22(b); + var dir = select(((a + b) * sinSign), (orthoA + orthoB), (dot(a, b) < 0f)); + return normalize(dir); + } + + fn midPoint_23(a: vec2f, b: vec2f) -> vec2f { + return (0.5 * (a + b)); + } + + fn addMul_24(a: vec2f, b: vec2f, f: f32) -> vec2f { + return (a + (b * f)); + } + + fn miterPoint_19(a: vec2f, b: vec2f) -> vec2f { + let sin_ = cross2d_14(a, b); + var bisection = bisectCcw_20(a, b); + let b2 = dot(b, b); + let cos_ = dot(a, b); + let diff = (b2 - cos_); + if (((diff * diff) < 1e-4f)) { + return midPoint_23(a, b); + } + if ((sin_ < 0f)) { + return (bisection * -1000000); + } + let t = (diff / sin_); + return addMul_24(a, rot90ccw_21(a), t); + } + + struct LimitAlongResult_26 { + a: vec2f, + b: vec2f, + limitWasHit: bool, + } + + fn limitTowardsMiddle_25(middle: vec2f, dir: vec2f, p1: vec2f, p2: vec2f) -> LimitAlongResult_26 { + let t1 = dot((p1 - middle), dir); + let t2 = dot((p2 - middle), dir); + if ((t1 <= t2)) { + return LimitAlongResult_26(p1, p2, false); + } + let t = clamp((t1 / (t1 - t2)), 0f, 1f); + var p = mix(p1, p2, t); + return LimitAlongResult_26(p, p, true); + } + + fn item_27(vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, _right: vec2f, dir: vec2f, _left: vec2f) -> vec2f { + var dirRight = rot90cw_22(dir); + var dirLeft = rot90ccw_21(dir); + var v0 = addMul_24(vu, dir, (-7.5f * V.radius)); + var v1 = addMul_24(V.position, addMul_24(dirRight, dir, -3f), (3f * V.radius)); + var v2 = addMul_24(V.position, vec2f(), (2f * V.radius)); + var v3 = addMul_24(V.position, addMul_24(dirLeft, dir, -3f), (3f * V.radius)); + var v4 = addMul_24(vd, dir, (-7.5f * V.radius)); + var points = array(v0, v1, v2, v3, v4); + if ((joinPath.depth >= 0i)) { + var remove = array(v0, v4); + let dm = (&remove[(joinPath.joinIndex & 1u)]); + return (*dm); + } + return points[(vertexIndex % 5u)]; + } + + fn miterPointNoCheck_29(a: vec2f, b: vec2f) -> vec2f { + var ab = (a + b); + return (ab * (2f / dot(ab, ab))); + } + + fn item_28(vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, right: vec2f, dir: vec2f, left: vec2f) -> vec2f { + let shouldJoin = (dot(dir, right) < 0f); + var dirRight = rot90cw_22(dir); + var dirLeft = rot90ccw_21(dir); + var u = select(miterPointNoCheck_29(right, dir), (dir + dirRight), shouldJoin); + var c = dir; + var d = select(miterPointNoCheck_29(dir, left), (dir + dirLeft), shouldJoin); + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var miterR = select(right, miterPointNoCheck_29(right, dirRight), shouldJoin); + var miterL = select(left, miterPointNoCheck_29(dirLeft, left), shouldJoin); + var parents = array(miterR, miterL); + let dm = (&parents[(joinIndex & 1u)]); + return addMul_24(V.position, (*dm), V.radius); + } + var v1 = addMul_24(V.position, u, V.radius); + var v2 = addMul_24(V.position, c, V.radius); + var v3 = addMul_24(V.position, d, V.radius); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + struct Intersection_32 { + valid: bool, + t: f32, + point: vec2f, + } + + fn intersectLines_31(A1: vec2f, A2: vec2f, B1: vec2f, B2: vec2f) -> Intersection_32 { + var a = (A2 - A1); + var b = (B2 - B1); + let axb = cross2d_14(a, b); + var AB = (B1 - A1); + let t = (cross2d_14(AB, b) / axb); + return Intersection_32((axb != 0f), t, addMul_24(A1, a, t)); + } + + fn bisectNoCheck_33(a: vec2f, b: vec2f) -> vec2f { + return normalize((a + b)); + } + + fn item_30(situationIndex: u32, vertexIndex: u32, joinPath: JoinPath_8, V: LineSegmentVertex_4, vu: vec2f, vd: vec2f, ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f, joinU: bool, joinD: bool) -> vec2f { + var midU = bisectCcw_20(ur, ul); + var midD = bisectCcw_20(dl, dr); + var midR = bisectCcw_20(ur, dr); + var midL = bisectCcw_20(dl, ul); + let shouldCross = ((situationIndex == 1u) || (situationIndex == 4u)); + var crossCenter = intersectLines_31(ul, dl, ur, dr).point; + var averageCenter = (((ur + ul) + (dl + dr)) * 0.25); + var uR = ur; + var u = midU; + var c = select(averageCenter, crossCenter, shouldCross); + var d = midD; + var dR = dr; + if ((situationIndex == 2u)) { + uR = ur; + u = midR; + c = midR; + d = midR; + dR = dr; + } + if ((situationIndex == 3u)) { + uR = ur; + u = midL; + c = midL; + d = midL; + dR = dr; + } + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = bisectCcw_20(d0, d1); + var path = joinPath.path; + for (var depth = joinPath.depth; (depth > 0i); depth -= 1i) { + let isLeftChild = ((path & 1u) == 0u); + d0 = select(dm, d0, isLeftChild); + d1 = select(d1, dm, isLeftChild); + dm = bisectNoCheck_33(d0, d1); + path >>= 1u; + } + return addMul_24(V.position, dm, V.radius); + } + var v1 = select(vu, addMul_24(V.position, u, V.radius), joinU); + var v2 = select(vu, addMul_24(V.position, c, V.radius), (joinU || joinD)); + var v3 = select(vd, addMul_24(V.position, d, V.radius), joinD); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn lineSegmentVariableWidth_6(vertexIndex: u32, A: LineSegmentVertex_4, B: LineSegmentVertex_4, C: LineSegmentVertex_4, D: LineSegmentVertex_4) -> LineSegmentOutput_10 { + var joinPath = getJoinVertexPath_7(vertexIndex); + var AB = (B.position - A.position); + var BC = (C.position - B.position); + var CD = (D.position - C.position); + let radiusABDelta = (A.radius - B.radius); + let radiusBCDelta = (B.radius - C.radius); + let radiusCDDelta = (C.radius - D.radius); + if ((dot(BC, BC) <= (radiusBCDelta * radiusBCDelta))) { + return LineSegmentOutput_10(vec2f(), 0u); + } + let isCapB = (dot(AB, AB) <= ((radiusABDelta * radiusABDelta) + 1e-12f)); + let isCapC = (dot(CD, CD) <= ((radiusCDDelta * radiusCDDelta) + 1e-12f)); + var eAB = externalNormals_11(AB, A.radius, B.radius); + var eBC = externalNormals_11(BC, B.radius, C.radius); + var eCD = externalNormals_11(CD, C.radius, D.radius); + var nBC = normalize(BC); + var nCB = (nBC * -1); + var d0 = eBC.n1; + var d4 = eBC.n2; + var d5 = eBC.n2; + var d9 = eBC.n1; + let situationIndexB = joinSituationIndex_13(eAB.n1, eBC.n1, eAB.n2, eBC.n2); + let situationIndexC = joinSituationIndex_13(eCD.n2, eBC.n2, eCD.n1, eBC.n1); + var joinBu = true; + var joinBd = true; + var joinCu = true; + var joinCd = true; + if (!isCapB) { + if ((((situationIndexB == 1u) || (situationIndexB == 5u)) || (dot(eBC.n2, eAB.n2) > JOIN_LIMIT_18))) { + d4 = miterPoint_19(eBC.n2, eAB.n2); + joinBd = false; + } + if ((((situationIndexB == 4u) || (situationIndexB == 5u)) || (dot(eAB.n1, eBC.n1) > JOIN_LIMIT_18))) { + d0 = miterPoint_19(eAB.n1, eBC.n1); + joinBu = false; + } + } + if (!isCapC) { + if ((((situationIndexC == 4u) || (situationIndexC == 5u)) || (dot(eCD.n2, eBC.n2) > JOIN_LIMIT_18))) { + d5 = miterPoint_19(eCD.n2, eBC.n2); + joinCd = false; + } + if ((((situationIndexC == 1u) || (situationIndexC == 5u)) || (dot(eBC.n1, eCD.n1) > JOIN_LIMIT_18))) { + d9 = miterPoint_19(eBC.n1, eCD.n1); + joinCu = false; + } + } + var v0 = addMul_24(B.position, d0, B.radius); + var v4 = addMul_24(B.position, d4, B.radius); + var v5 = addMul_24(C.position, d5, C.radius); + var v9 = addMul_24(C.position, d9, C.radius); + var midBC = midPoint_23(B.position, C.position); + var tBC1 = rot90cw_22(eBC.n1); + var tBC2 = rot90ccw_21(eBC.n2); + var limU = limitTowardsMiddle_25(midBC, tBC1, v0, v9); + var limD = limitTowardsMiddle_25(midBC, tBC2, v4, v5); + v0 = limU.a; + v9 = limU.b; + v4 = limD.a; + v5 = limD.b; + let isCSide = (joinPath.joinIndex >= 2u); + var situationIndex = situationIndexB; + var V = B; + var isCap = isCapB; + var j1 = eAB.n1; + var j2 = eBC.n1; + var j3 = eAB.n2; + var j4 = eBC.n2; + var vu = v0; + var vd = v4; + var joinU = joinBu; + var joinD = joinBd; + if (isCSide) { + situationIndex = situationIndexC; + V = C; + isCap = isCapC; + j4 = eBC.n1; + j3 = eCD.n1; + j2 = eBC.n2; + j1 = eCD.n2; + vu = v5; + vd = v9; + joinU = joinCd; + joinD = joinCu; + } + let joinIndex = joinPath.joinIndex; + if ((vertexIndex >= 10u)) { + var shouldJoin = array(u32(joinBu), u32(joinBd), u32(joinCd), u32(joinCu)); + if ((shouldJoin[joinIndex] == 0u)) { + var noJoinPoints = array(v0, v4, v5, v9); + let vertexPosition2 = (&noJoinPoints[joinIndex]); + return LineSegmentOutput_10((*vertexPosition2), situationIndex); + } + } + var vertexPosition = vec2f(); + if (isCap) { + if (isCSide) { + vertexPosition = item_27(vertexIndex, joinPath, V, vu, vd, j2, nBC, j4); + } + else { + vertexPosition = item_28(vertexIndex, joinPath, V, vu, vd, j2, nCB, j4); + } + } + else { + vertexPosition = item_30(situationIndex, vertexIndex, joinPath, V, vu, vd, j1, j2, j3, j4, joinU, joinD); + } + return LineSegmentOutput_10(vertexPosition, situationIndex); + } + + fn uvToLineSegment_34(A: vec2f, B: vec2f, point: vec2f) -> vec2f { + var p = (point - A); + var AB = (B - A); + let x = (dot(p, AB) / dot(AB, AB)); + let y = cross2d_14(normalize(AB), p); + return vec2f(x, y); + } + + struct mainVertex_Input_35 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn mainVertex_0(_arg_0: mainVertex_Input_35) -> mainVertex_Output_5 { + let t = uniforms_1.time; + var A = item_3(_arg_0.instanceIndex, t); + var B = item_3((_arg_0.instanceIndex + 1u), t); + var C = item_3((_arg_0.instanceIndex + 2u), t); + var D = item_3((_arg_0.instanceIndex + 3u), t); + if (((((A.radius < 0f) || (B.radius < 0f)) || (C.radius < 0f)) || (D.radius < 0f))) { + return mainVertex_Output_5(vec4f(), vec2f(), vec2f(), 0u, 0u, 0u); + } + var result = lineSegmentVariableWidth_6(_arg_0.vertexIndex, A, B, C, D); + var uv = uvToLineSegment_34(B.position, C.position, result.vertexPosition); + return mainVertex_Output_5(vec4f(result.vertexPosition, 0f, 1f), result.vertexPosition, uv, _arg_0.instanceIndex, _arg_0.vertexIndex, result.situationIndex); + } + + struct mainFragment_Input_37 { + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + @builtin(front_facing) frontFacing: bool, + @builtin(position) screenPosition: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + } + + @fragment fn mainFragment_36(_arg_0: mainFragment_Input_37) -> @location(0) vec4f { + let fillType2 = uniforms_1.fillType; + if ((fillType2 == 1u)) { + return mix(vec4f(0.7699999809265137, 0.38999998569488525, 1, 0.5), vec4f(0.10999999940395355, 0.4399999976158142, 0.9399999976158142, 0.5), ((_arg_0.position.x * 0.5f) + 0.5f)); + } + var color = vec3f(); + var colors = array(vec3f(1, 0, 0), vec3f(0, 1, 0), vec3f(0, 0, 1), vec3f(1, 0, 1), vec3f(1, 1, 0), vec3f(0, 1, 1), vec3f(0.75, 0.25, 0.25), vec3f(0.25, 0.75, 0.25), vec3f(0.25, 0.25, 0.75)); + if ((fillType2 == 2u)) { + color = colors[(_arg_0.instanceIndex % 9u)]; + } + if ((fillType2 == 3u)) { + color = colors[(_arg_0.vertexIndex % 9u)]; + } + if ((fillType2 == 4u)) { + color = colors[(_arg_0.situationIndex % 9u)]; + } + if ((fillType2 == 5u)) { + color = vec3f(_arg_0.uv.x, cos((_arg_0.uv.y * 100f)), 0f); + } + if (_arg_0.frontFacing) { + return vec4f(color, 0.5f); + } + return vec4f(color, select(0f, 1f, (((u32(_arg_0.screenPosition.x) >> 3u) % 2u) != ((u32(_arg_0.screenPosition.y) >> 3u) % 2u)))); + } + + struct outlineFragment_Input_39 { + @builtin(front_facing) _unused: bool, + } + + @fragment fn outlineFragment_38(_arg_0: outlineFragment_Input_39) -> @location(0) vec4f { + return vec4f(0, 0, 0, 0.20000000298023224); + } + + struct centerlineVertex_Output_41 { + @builtin(position) outPos: vec4f, + } + + struct centerlineVertex_Input_42 { + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn centerlineVertex_40(_arg_0: centerlineVertex_Input_42) -> centerlineVertex_Output_41 { + let t = uniforms_1.time; + var vertex = item_3(_arg_0.vertexIndex, t); + if ((vertex.radius < 0f)) { + return centerlineVertex_Output_41(vec4f()); + } + return centerlineVertex_Output_41(vec4f(vertex.position, 0f, 1f)); + } + + struct circlesVertex_Output_44 { + @builtin(position) outPos: vec4f, + } + + struct circlesVertex_Input_45 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn circlesVertex_43(_arg_0: circlesVertex_Input_45) -> circlesVertex_Output_44 { + let t = uniforms_1.time; + var vertex = item_3(_arg_0.instanceIndex, t); + if ((vertex.radius < 0f)) { + return circlesVertex_Output_44(vec4f()); + } + let step = clamp((0.007853981633974483f / vertex.radius), 0.02454369260617026f, 0.39269908169872414f); + let angle = min(6.283185307179586f, (step * f32(_arg_0.vertexIndex))); + var unit = vec2f(cos(angle), sin(angle)); + return circlesVertex_Output_44(vec4f(addMul_24(vertex.position, unit, vertex.radius), 0f, 1f)); + } + + struct Uniforms_2 { + time: f32, + fillType: u32, + } + + @group(0) @binding(0) var uniforms_1: Uniforms_2; + + const segmentSide_4: array = array(-1f, -1f, 1f, 1f); + + struct LineSegmentVertex_5 { + position: vec2f, + radius: f32, + } + + fn item_3(vertexIndex: u32, time: f32) -> LineSegmentVertex_5 { + var side = segmentSide_4[vertexIndex]; + let r = sin((time + select(0., 1.5707963267948966, (side == -1f)))); + let radius = ((0.4f * r) * r); + return LineSegmentVertex_5(vec2f(((0.5f * side) * cos(time)), ((0.5f * side) * sin(time))), radius); + } + + struct mainVertex_Output_6 { + @builtin(position) outPos: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + } + + struct JoinPath_9 { + joinIndex: u32, + path: u32, + depth: i32, + } + + fn getJoinParent_10(i: u32) -> u32 { + return ((i - 4u) >> 1u); + } + + fn getJoinVertexPath_8(vertexIndex: u32) -> JoinPath_9 { + var lookup = array(0u, 0u, 0u, 1u, 1u, 2u, 2u, 2u, 3u, 3u); + if ((vertexIndex < 10u)) { + return JoinPath_9(lookup[vertexIndex], 0u, -1i); + } + var joinIndex = (vertexIndex - 10u); + var depth = 0; + var path = 0u; + while ((joinIndex >= 4u)) { + path = ((path << 1u) | (joinIndex & 1u)); + joinIndex = getJoinParent_10(joinIndex); + depth += 1i; + } + return JoinPath_9(joinIndex, path, depth); + } + + struct LineSegmentOutput_11 { + vertexPosition: vec2f, + situationIndex: u32, + } + + struct ExternalNormals_13 { + n1: vec2f, + n2: vec2f, + } + + fn externalNormals_12(distance: vec2f, r1: f32, r2: f32) -> ExternalNormals_13 { + var dNorm = normalize(distance); + let expCos = ((r1 - r2) / length(distance)); + let expSin = sqrt(max(0f, (1f - (expCos * expCos)))); + let a = (dNorm.x * expCos); + let b = (dNorm.y * expSin); + let c = (dNorm.x * expSin); + let d = (dNorm.y * expCos); + var n1 = vec2f((a - b), (c + d)); + var n2 = vec2f((a + b), (-(c) + d)); + return ExternalNormals_13(n1, n2); + } + + fn cross2d_15(a: vec2f, b: vec2f) -> f32 { + return ((a.x * b.y) - (a.y * b.x)); + } + + fn isCCW_16(aX: f32, aYSign: bool, bX: f32, bYSign: bool) -> bool { + let sameSide = (aYSign == bYSign); + return select(aYSign, (aYSign == (aX >= bX)), sameSide); + } + + const lookup_18: array = array(5u, 3u, 4u, 3u, 2u, 1u, 0u, 0u); + + fn rank3_17(aGb: bool, bGc: bool, aGc: bool) -> u32 { + let code = (((u32(aGb) << 2u) | (u32(bGc) << 1u)) | u32(aGc)); + return lookup_18[code]; + } + + fn joinSituationIndex_14(ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f) -> u32 { + let crossUL = cross2d_15(ur, ul); + let crossDL = cross2d_15(ur, dl); + let crossDR = cross2d_15(ur, dr); + let signUL = (crossUL >= 0f); + let signDL = (crossDL >= 0f); + let signDR = (crossDR >= 0f); + let dotUL = dot(ur, ul); + let dotDL = dot(ur, dl); + let dotDR = dot(ur, dr); + return rank3_17(isCCW_16(dotUL, signUL, dotDL, signDL), isCCW_16(dotDL, signDL, dotDR, signDR), isCCW_16(dotUL, signUL, dotDR, signDR)); + } + + const JOIN_LIMIT_19: f32 = 0.999f; + + fn rot90ccw_22(v: vec2f) -> vec2f { + return vec2f(-(v.y), v.x); + } + + fn rot90cw_23(v: vec2f) -> vec2f { + return vec2f(v.y, -(v.x)); + } + + fn bisectCcw_21(a: vec2f, b: vec2f) -> vec2f { + let sin = cross2d_15(a, b); + let sinSign = select(-1f, 1f, (sin >= 0f)); + var orthoA = rot90ccw_22(a); + var orthoB = rot90cw_23(b); + var dir = select(((a + b) * sinSign), (orthoA + orthoB), (dot(a, b) < 0f)); + return normalize(dir); + } + + fn midPoint_24(a: vec2f, b: vec2f) -> vec2f { + return (0.5 * (a + b)); + } + + fn addMul_25(a: vec2f, b: vec2f, f: f32) -> vec2f { + return (a + (b * f)); + } + + fn miterPoint_20(a: vec2f, b: vec2f) -> vec2f { + let sin_ = cross2d_15(a, b); + var bisection = bisectCcw_21(a, b); + let b2 = dot(b, b); + let cos_ = dot(a, b); + let diff = (b2 - cos_); + if (((diff * diff) < 1e-4f)) { + return midPoint_24(a, b); + } + if ((sin_ < 0f)) { + return (bisection * -1000000); + } + let t = (diff / sin_); + return addMul_25(a, rot90ccw_22(a), t); + } + + struct LimitAlongResult_27 { + a: vec2f, + b: vec2f, + limitWasHit: bool, + } + + fn limitTowardsMiddle_26(middle: vec2f, dir: vec2f, p1: vec2f, p2: vec2f) -> LimitAlongResult_27 { + let t1 = dot((p1 - middle), dir); + let t2 = dot((p2 - middle), dir); + if ((t1 <= t2)) { + return LimitAlongResult_27(p1, p2, false); + } + let t = clamp((t1 / (t1 - t2)), 0f, 1f); + var p = mix(p1, p2, t); + return LimitAlongResult_27(p, p, true); + } + + fn item_28(vertexIndex: u32, joinPath: JoinPath_9, V: LineSegmentVertex_5, vu: vec2f, vd: vec2f, right: vec2f, dir: vec2f, left: vec2f) -> vec2f { + if ((joinPath.depth >= 0i)) { + var remove = array(right, left); + var dm = remove[(joinPath.joinIndex & 1u)]; + return addMul_25(V.position, dm, V.radius); + } + var v1 = addMul_25(V.position, (right + dir), V.radius); + var v2 = addMul_25(V.position, midPoint_24(right, left), V.radius); + var v3 = addMul_25(V.position, (left + dir), V.radius); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn bisectNoCheck_30(a: vec2f, b: vec2f) -> vec2f { + return normalize((a + b)); + } + + fn item_29(vertexIndex: u32, joinPath: JoinPath_9, V: LineSegmentVertex_5, vu: vec2f, vd: vec2f, right: vec2f, dir: vec2f, left: vec2f) -> vec2f { + var uR = right; + var u = dir; + var c = dir; + var d = dir; + var dR = left; + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = bisectCcw_21(d0, d1); + var path = joinPath.path; + for (var depth = joinPath.depth; (depth > 0i); depth -= 1i) { + let isLeftChild = ((path & 1u) == 0u); + d0 = select(dm, d0, isLeftChild); + d1 = select(d1, dm, isLeftChild); + dm = bisectNoCheck_30(d0, d1); + path >>= 1u; + } + return addMul_25(V.position, dm, V.radius); + } + var v1 = addMul_25(V.position, u, V.radius); + var v2 = addMul_25(V.position, c, V.radius); + var v3 = addMul_25(V.position, d, V.radius); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn miterLimit_32(miter: vec2f, limitRatio: f32) -> vec2f { + let m2 = dot(miter, miter); + if ((m2 > (limitRatio * limitRatio))) { + return (normalize(miter) * ((((limitRatio - 1f) * ((limitRatio * limitRatio) - 1f)) / (m2 - 1f)) + 1f)); + } + return miter; + } + + struct Intersection_34 { + valid: bool, + t: f32, + point: vec2f, + } + + fn intersectLines_33(A1: vec2f, A2: vec2f, B1: vec2f, B2: vec2f) -> Intersection_34 { + var a = (A2 - A1); + var b = (B2 - B1); + let axb = cross2d_15(a, b); + var AB = (B1 - A1); + let t = (cross2d_15(AB, b) / axb); + return Intersection_34((axb != 0f), t, addMul_25(A1, a, t)); + } + + fn item_31(situationIndex: u32, vertexIndex: u32, joinPath: JoinPath_9, V: LineSegmentVertex_5, vu: vec2f, vd: vec2f, ul: vec2f, ur: vec2f, dl: vec2f, dr: vec2f, joinU: bool, joinD: bool) -> vec2f { + var miterU = miterPoint_20(ur, ul); + var miterD = miterPoint_20(dl, dr); + miterU = miterLimit_32(miterU, 2f); + miterD = miterLimit_32(miterD, 2f); + let shouldCross = ((situationIndex == 1u) || (situationIndex == 4u)); + var crossCenter = intersectLines_33(ul, dl, ur, dr).point; + var averageCenter = ((normalize(miterU) + normalize(miterD)) * 0.5); + var uR = ur; + var u = miterU; + var c = select(averageCenter, crossCenter, shouldCross); + var d = miterD; + var dR = dr; + if ((situationIndex == 2u)) { + var mid = bisectCcw_21(ur, dr); + uR = ur; + u = mid; + c = mid; + d = mid; + dR = dr; + } + if ((situationIndex == 3u)) { + var mid = bisectCcw_21(dl, ul); + uR = ur; + u = mid; + c = mid; + d = mid; + dR = dr; + } + let joinIndex = joinPath.joinIndex; + if ((joinPath.depth >= 0i)) { + var parents = array(uR, u, d, dR); + var d0 = parents[((joinIndex * 2u) & 3u)]; + var d1 = parents[(((joinIndex * 2u) + 1u) & 3u)]; + var dm = miterPoint_20(d0, d1); + return addMul_25(V.position, dm, V.radius); + } + var v1 = select(vu, addMul_25(V.position, u, V.radius), joinU); + var v2 = select(vu, addMul_25(V.position, c, V.radius), (joinU || joinD)); + var v3 = select(vd, addMul_25(V.position, d, V.radius), joinD); + var points = array(vu, v1, v2, v3, vd); + return points[(vertexIndex % 5u)]; + } + + fn lineSegmentVariableWidth_7(vertexIndex: u32, A: LineSegmentVertex_5, B: LineSegmentVertex_5, C: LineSegmentVertex_5, D: LineSegmentVertex_5) -> LineSegmentOutput_11 { + var joinPath = getJoinVertexPath_8(vertexIndex); + var AB = (B.position - A.position); + var BC = (C.position - B.position); + var CD = (D.position - C.position); + let radiusABDelta = (A.radius - B.radius); + let radiusBCDelta = (B.radius - C.radius); + let radiusCDDelta = (C.radius - D.radius); + if ((dot(BC, BC) <= (radiusBCDelta * radiusBCDelta))) { + return LineSegmentOutput_11(vec2f(), 0u); + } + let isCapB = (dot(AB, AB) <= ((radiusABDelta * radiusABDelta) + 1e-12f)); + let isCapC = (dot(CD, CD) <= ((radiusCDDelta * radiusCDDelta) + 1e-12f)); + var eAB = externalNormals_12(AB, A.radius, B.radius); + var eBC = externalNormals_12(BC, B.radius, C.radius); + var eCD = externalNormals_12(CD, C.radius, D.radius); + var nBC = normalize(BC); + var nCB = (nBC * -1); + var d0 = eBC.n1; + var d4 = eBC.n2; + var d5 = eBC.n2; + var d9 = eBC.n1; + let situationIndexB = joinSituationIndex_14(eAB.n1, eBC.n1, eAB.n2, eBC.n2); + let situationIndexC = joinSituationIndex_14(eCD.n2, eBC.n2, eCD.n1, eBC.n1); + var joinBu = true; + var joinBd = true; + var joinCu = true; + var joinCd = true; + if (!isCapB) { + if ((((situationIndexB == 1u) || (situationIndexB == 5u)) || (dot(eBC.n2, eAB.n2) > JOIN_LIMIT_19))) { + d4 = miterPoint_20(eBC.n2, eAB.n2); + joinBd = false; + } + if ((((situationIndexB == 4u) || (situationIndexB == 5u)) || (dot(eAB.n1, eBC.n1) > JOIN_LIMIT_19))) { + d0 = miterPoint_20(eAB.n1, eBC.n1); + joinBu = false; + } + } + if (!isCapC) { + if ((((situationIndexC == 4u) || (situationIndexC == 5u)) || (dot(eCD.n2, eBC.n2) > JOIN_LIMIT_19))) { + d5 = miterPoint_20(eCD.n2, eBC.n2); + joinCd = false; + } + if ((((situationIndexC == 1u) || (situationIndexC == 5u)) || (dot(eBC.n1, eCD.n1) > JOIN_LIMIT_19))) { + d9 = miterPoint_20(eBC.n1, eCD.n1); + joinCu = false; + } + } + var v0 = addMul_25(B.position, d0, B.radius); + var v4 = addMul_25(B.position, d4, B.radius); + var v5 = addMul_25(C.position, d5, C.radius); + var v9 = addMul_25(C.position, d9, C.radius); + var midBC = midPoint_24(B.position, C.position); + var tBC1 = rot90cw_23(eBC.n1); + var tBC2 = rot90ccw_22(eBC.n2); + var limU = limitTowardsMiddle_26(midBC, tBC1, v0, v9); + var limD = limitTowardsMiddle_26(midBC, tBC2, v4, v5); + v0 = limU.a; + v9 = limU.b; + v4 = limD.a; + v5 = limD.b; + let isCSide = (joinPath.joinIndex >= 2u); + var situationIndex = situationIndexB; + var V = B; + var isCap = isCapB; + var j1 = eAB.n1; + var j2 = eBC.n1; + var j3 = eAB.n2; + var j4 = eBC.n2; + var vu = v0; + var vd = v4; + var joinU = joinBu; + var joinD = joinBd; + if (isCSide) { + situationIndex = situationIndexC; + V = C; + isCap = isCapC; + j4 = eBC.n1; + j3 = eCD.n1; + j2 = eBC.n2; + j1 = eCD.n2; + vu = v5; + vd = v9; + joinU = joinCd; + joinD = joinCu; + } + let joinIndex = joinPath.joinIndex; + if ((vertexIndex >= 10u)) { + var shouldJoin = array(u32(joinBu), u32(joinBd), u32(joinCd), u32(joinCu)); + if ((shouldJoin[joinIndex] == 0u)) { + var noJoinPoints = array(v0, v4, v5, v9); + let vertexPosition2 = (&noJoinPoints[joinIndex]); + return LineSegmentOutput_11((*vertexPosition2), situationIndex); + } + } + var vertexPosition = vec2f(); + if (isCap) { + if (isCSide) { + vertexPosition = item_28(vertexIndex, joinPath, V, vu, vd, j2, nBC, j4); + } + else { + vertexPosition = item_29(vertexIndex, joinPath, V, vu, vd, j2, nCB, j4); + } + } + else { + vertexPosition = item_31(situationIndex, vertexIndex, joinPath, V, vu, vd, j1, j2, j3, j4, joinU, joinD); + } + return LineSegmentOutput_11(vertexPosition, situationIndex); + } + + fn uvToLineSegment_35(A: vec2f, B: vec2f, point: vec2f) -> vec2f { + var p = (point - A); + var AB = (B - A); + let x = (dot(p, AB) / dot(AB, AB)); + let y = cross2d_15(normalize(AB), p); + return vec2f(x, y); + } + + struct mainVertex_Input_36 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn mainVertex_0(_arg_0: mainVertex_Input_36) -> mainVertex_Output_6 { + let t = uniforms_1.time; + var A = item_3(_arg_0.instanceIndex, t); + var B = item_3((_arg_0.instanceIndex + 1u), t); + var C = item_3((_arg_0.instanceIndex + 2u), t); + var D = item_3((_arg_0.instanceIndex + 3u), t); + if (((((A.radius < 0f) || (B.radius < 0f)) || (C.radius < 0f)) || (D.radius < 0f))) { + return mainVertex_Output_6(vec4f(), vec2f(), vec2f(), 0u, 0u, 0u); + } + var result = lineSegmentVariableWidth_7(_arg_0.vertexIndex, A, B, C, D); + var uv = uvToLineSegment_35(B.position, C.position, result.vertexPosition); + return mainVertex_Output_6(vec4f(result.vertexPosition, 0f, 1f), result.vertexPosition, uv, _arg_0.instanceIndex, _arg_0.vertexIndex, result.situationIndex); + } + + struct mainFragment_Input_38 { + @location(2) @interpolate(flat) instanceIndex: u32, + @location(3) @interpolate(flat) vertexIndex: u32, + @location(4) @interpolate(flat) situationIndex: u32, + @builtin(front_facing) frontFacing: bool, + @builtin(position) screenPosition: vec4f, + @location(0) position: vec2f, + @location(1) uv: vec2f, + } + + @fragment fn mainFragment_37(_arg_0: mainFragment_Input_38) -> @location(0) vec4f { + let fillType2 = uniforms_1.fillType; + if ((fillType2 == 1u)) { + return mix(vec4f(0.7699999809265137, 0.38999998569488525, 1, 0.5), vec4f(0.10999999940395355, 0.4399999976158142, 0.9399999976158142, 0.5), ((_arg_0.position.x * 0.5f) + 0.5f)); + } + var color = vec3f(); + var colors = array(vec3f(1, 0, 0), vec3f(0, 1, 0), vec3f(0, 0, 1), vec3f(1, 0, 1), vec3f(1, 1, 0), vec3f(0, 1, 1), vec3f(0.75, 0.25, 0.25), vec3f(0.25, 0.75, 0.25), vec3f(0.25, 0.25, 0.75)); + if ((fillType2 == 2u)) { + color = colors[(_arg_0.instanceIndex % 9u)]; + } + if ((fillType2 == 3u)) { + color = colors[(_arg_0.vertexIndex % 9u)]; + } + if ((fillType2 == 4u)) { + color = colors[(_arg_0.situationIndex % 9u)]; + } + if ((fillType2 == 5u)) { + color = vec3f(_arg_0.uv.x, cos((_arg_0.uv.y * 100f)), 0f); + } + if (_arg_0.frontFacing) { + return vec4f(color, 0.5f); + } + return vec4f(color, select(0f, 1f, (((u32(_arg_0.screenPosition.x) >> 3u) % 2u) != ((u32(_arg_0.screenPosition.y) >> 3u) % 2u)))); + } + + struct outlineFragment_Input_40 { + @builtin(front_facing) _unused: bool, + } + + @fragment fn outlineFragment_39(_arg_0: outlineFragment_Input_40) -> @location(0) vec4f { + return vec4f(0, 0, 0, 0.20000000298023224); + } + + struct centerlineVertex_Output_42 { + @builtin(position) outPos: vec4f, + } + + struct centerlineVertex_Input_43 { + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn centerlineVertex_41(_arg_0: centerlineVertex_Input_43) -> centerlineVertex_Output_42 { + let t = uniforms_1.time; + var vertex = item_3(_arg_0.vertexIndex, t); + if ((vertex.radius < 0f)) { + return centerlineVertex_Output_42(vec4f()); + } + return centerlineVertex_Output_42(vec4f(vertex.position, 0f, 1f)); + } + + struct circlesVertex_Output_45 { + @builtin(position) outPos: vec4f, + } + + struct circlesVertex_Input_46 { + @builtin(instance_index) instanceIndex: u32, + @builtin(vertex_index) vertexIndex: u32, + } + + @vertex fn circlesVertex_44(_arg_0: circlesVertex_Input_46) -> circlesVertex_Output_45 { + let t = uniforms_1.time; + var vertex = item_3(_arg_0.instanceIndex, t); + if ((vertex.radius < 0f)) { + return circlesVertex_Output_45(vec4f()); + } + let step = clamp((0.007853981633974483f / vertex.radius), 0.02454369260617026f, 0.39269908169872414f); + let angle = min(6.283185307179586f, (step * f32(_arg_0.vertexIndex))); + var unit = vec2f(cos(angle), sin(angle)); + return circlesVertex_Output_45(vec4f(addMul_25(vertex.position, unit, vertex.radius), 0f, 1f)); + }" + `); + }); +});