221 lines
6.0 KiB
GLSL
221 lines
6.0 KiB
GLSL
#version {{version}}
|
|
// Automatically generated from files in pathfinder/shaders/. Do not edit!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#extension GL_GOOGLE_include_directive : enable
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
precision highp float;
|
|
|
|
|
|
|
|
|
|
|
|
layout(local_size_x = 64)in;
|
|
|
|
uniform mat2 uTransform;
|
|
uniform vec2 uTranslation;
|
|
uniform int uPathCount;
|
|
uniform int uLastBatchSegmentIndex;
|
|
uniform int uMaxMicrolineCount;
|
|
|
|
layout(std430, binding = 0)buffer bComputeIndirectParams {
|
|
|
|
|
|
|
|
|
|
restrict uint iComputeIndirectParams[];
|
|
};
|
|
|
|
|
|
layout(std430, binding = 1)buffer bDiceMetadata {
|
|
|
|
|
|
|
|
|
|
restrict readonly uvec4 iDiceMetadata[];
|
|
};
|
|
|
|
layout(std430, binding = 2)buffer bPoints {
|
|
restrict readonly vec2 iPoints[];
|
|
};
|
|
|
|
layout(std430, binding = 3)buffer bInputIndices {
|
|
restrict readonly uvec2 iInputIndices[];
|
|
};
|
|
|
|
layout(std430, binding = 4)buffer bMicrolines {
|
|
|
|
|
|
|
|
|
|
restrict uvec4 iMicrolines[];
|
|
};
|
|
|
|
void emitMicroline(vec4 microlineSegment, uint pathIndex, uint outputMicrolineIndex){
|
|
if(outputMicrolineIndex >= uMaxMicrolineCount)
|
|
return;
|
|
|
|
ivec4 microlineSubpixels = ivec4(round(clamp(microlineSegment, - 32768.0, 32767.0)* 256.0));
|
|
ivec4 microlinePixels = ivec4(floor(vec4(microlineSubpixels)/ 256.0));
|
|
ivec4 microlineFractPixels = microlineSubpixels - microlinePixels * 256;
|
|
|
|
iMicrolines[outputMicrolineIndex]=
|
|
uvec4((uint(microlinePixels . x)& 0xffff)|(uint(microlinePixels . y)<< 16),
|
|
(uint(microlinePixels . z)& 0xffff)|(uint(microlinePixels . w)<< 16),
|
|
uint(microlineFractPixels . x)|(uint(microlineFractPixels . y)<< 8)|
|
|
(uint(microlineFractPixels . z)<< 16)|(uint(microlineFractPixels . w)<< 24),
|
|
pathIndex);
|
|
}
|
|
|
|
|
|
bool curveIsFlat(vec4 baseline, vec4 ctrl){
|
|
vec4 uv = vec4(3.0)* ctrl - vec4(2.0)* baseline - baseline . zwxy;
|
|
uv *= uv;
|
|
uv = max(uv, uv . zwxy);
|
|
return uv . x + uv . y <= 16.0 * 0.25 * 0.25;
|
|
}
|
|
|
|
void subdivideCurve(vec4 baseline,
|
|
vec4 ctrl,
|
|
float t,
|
|
out vec4 prevBaseline,
|
|
out vec4 prevCtrl,
|
|
out vec4 nextBaseline,
|
|
out vec4 nextCtrl){
|
|
vec2 p0 = baseline . xy, p1 = ctrl . xy, p2 = ctrl . zw, p3 = baseline . zw;
|
|
vec2 p0p1 = mix(p0, p1, t), p1p2 = mix(p1, p2, t), p2p3 = mix(p2, p3, t);
|
|
vec2 p0p1p2 = mix(p0p1, p1p2, t), p1p2p3 = mix(p1p2, p2p3, t);
|
|
vec2 p0p1p2p3 = mix(p0p1p2, p1p2p3, t);
|
|
prevBaseline = vec4(p0, p0p1p2p3);
|
|
prevCtrl = vec4(p0p1, p0p1p2);
|
|
nextBaseline = vec4(p0p1p2p3, p3);
|
|
nextCtrl = vec4(p1p2p3, p2p3);
|
|
}
|
|
|
|
vec2 sampleCurve(vec4 baseline, vec4 ctrl, float t){
|
|
vec2 p0 = baseline . xy, p1 = ctrl . xy, p2 = ctrl . zw, p3 = baseline . zw;
|
|
vec2 p0p1 = mix(p0, p1, t), p1p2 = mix(p1, p2, t), p2p3 = mix(p2, p3, t);
|
|
vec2 p0p1p2 = mix(p0p1, p1p2, t), p1p2p3 = mix(p1p2, p2p3, t);
|
|
return mix(p0p1p2, p1p2p3, t);
|
|
}
|
|
|
|
vec2 sampleLine(vec4 line, float t){
|
|
return mix(line . xy, line . zw, t);
|
|
}
|
|
|
|
vec2 getPoint(uint pointIndex){
|
|
return uTransform * iPoints[pointIndex]+ uTranslation;
|
|
}
|
|
|
|
void main(){
|
|
uint batchSegmentIndex = gl_GlobalInvocationID . x;
|
|
if(batchSegmentIndex >= uLastBatchSegmentIndex)
|
|
return;
|
|
|
|
|
|
uint lowPathIndex = 0, highPathIndex = uint(uPathCount);
|
|
int iteration = 0;
|
|
while(iteration < 1024 && lowPathIndex + 1 < highPathIndex){
|
|
uint midPathIndex = lowPathIndex +(highPathIndex - lowPathIndex)/ 2;
|
|
uint midBatchSegmentIndex = iDiceMetadata[midPathIndex]. z;
|
|
if(batchSegmentIndex < midBatchSegmentIndex){
|
|
highPathIndex = midPathIndex;
|
|
} else {
|
|
lowPathIndex = midPathIndex;
|
|
if(batchSegmentIndex == midBatchSegmentIndex)
|
|
break;
|
|
}
|
|
iteration ++;
|
|
}
|
|
|
|
uint batchPathIndex = lowPathIndex;
|
|
uvec4 diceMetadata = iDiceMetadata[batchPathIndex];
|
|
uint firstGlobalSegmentIndexInPath = diceMetadata . y;
|
|
uint firstBatchSegmentIndexInPath = diceMetadata . z;
|
|
uint globalSegmentIndex = batchSegmentIndex - firstBatchSegmentIndexInPath +
|
|
firstGlobalSegmentIndexInPath;
|
|
|
|
uvec2 inputIndices = iInputIndices[globalSegmentIndex];
|
|
uint fromPointIndex = inputIndices . x, flagsPathIndex = inputIndices . y;
|
|
|
|
uint toPointIndex = fromPointIndex;
|
|
if((flagsPathIndex & 0x40000000u)!= 0u)
|
|
toPointIndex += 3;
|
|
else if((flagsPathIndex & 0x80000000u)!= 0u)
|
|
toPointIndex += 2;
|
|
else
|
|
toPointIndex += 1;
|
|
|
|
vec4 baseline = vec4(getPoint(fromPointIndex), getPoint(toPointIndex));
|
|
|
|
|
|
|
|
|
|
|
|
vec4 ctrl = vec4(0.0);
|
|
float segmentCountF;
|
|
bool isCurve =(flagsPathIndex &(0x40000000u |
|
|
0x80000000u))!= 0;
|
|
if(isCurve){
|
|
vec2 ctrl0 = getPoint(fromPointIndex + 1);
|
|
if((flagsPathIndex & 0x80000000u)!= 0){
|
|
vec2 ctrl0_2 = ctrl0 * vec2(2.0);
|
|
ctrl =(baseline +(ctrl0 * vec2(2.0)). xyxy)* vec4(1.0 / 3.0);
|
|
} else {
|
|
ctrl = vec4(ctrl0, getPoint(fromPointIndex + 2));
|
|
}
|
|
vec2 bound = vec2(6.0)* max(abs(ctrl . zw - 2.0 * ctrl . xy + baseline . xy),
|
|
abs(baseline . zw - 2.0 * ctrl . zw + ctrl . xy));
|
|
segmentCountF = sqrt(length(bound)/(8.0 * 0.25));
|
|
} else {
|
|
segmentCountF = length(baseline . zw - baseline . xy)/ 16.0;
|
|
}
|
|
|
|
|
|
int segmentCount = max(int(ceil(segmentCountF)), 1);
|
|
uint firstOutputMicrolineIndex =
|
|
atomicAdd(iComputeIndirectParams[3],
|
|
segmentCount);
|
|
|
|
float prevT = 0.0;
|
|
vec2 prevPoint = baseline . xy;
|
|
for(int segmentIndex = 0;segmentIndex < segmentCount;segmentIndex ++){
|
|
float nextT = float(segmentIndex + 1)/ float(segmentCount);
|
|
vec2 nextPoint;
|
|
if(isCurve)
|
|
nextPoint = sampleCurve(baseline, ctrl, nextT);
|
|
else
|
|
nextPoint = sampleLine(baseline, nextT);
|
|
emitMicroline(vec4(prevPoint, nextPoint),
|
|
batchPathIndex,
|
|
firstOutputMicrolineIndex + segmentIndex);
|
|
prevT = nextT;
|
|
prevPoint = nextPoint;
|
|
}
|
|
}
|
|
|