37 for (
size_t screenIndex = 0; screenIndex <
m_screens.size(); screenIndex++) {
38 const auto& screen =
m_screens[screenIndex];
39 const auto& paths = screen.getPaths();
41 for (
const auto& path : paths) {
42 const auto& commands = path->getCommandQueue();
43 if (commands.empty()) {
48 uint32_t commandSize = commands.size();
56 Vec4 bounds = path->getBoundingRect();
58 addRectangle(screenIndex, commandOffset, commandSize, bounds);
66 float left = bounds.
x;
68 float right = bounds.
x + bounds.
z;
69 float bottom = bounds.
y + bounds.
w;
71 uint32_t baseIndex =
m_mesh->getVertexCount();
73 m_mesh->addVertex(
Vec2(left, top), commandOffset, commandSize, screenId);
75 m_mesh->addVertex(
Vec2(right, top), commandOffset, commandSize, screenId);
77 m_mesh->addVertex(
Vec2(left, bottom), commandOffset, commandSize, screenId);
79 m_mesh->addVertex(
Vec2(right, bottom), commandOffset, commandSize, screenId);
81 m_mesh->addIndex(baseIndex);
82 m_mesh->addIndex(baseIndex + 1);
83 m_mesh->addIndex(baseIndex + 2);
85 m_mesh->addIndex(baseIndex + 1);
86 m_mesh->addIndex(baseIndex + 3);
87 m_mesh->addIndex(baseIndex + 2);
122 m_mesh->reserveIndices(200);
123 m_mesh->reserveVertices(200);
152 if (projectionMatrix)
177ShaderOut main(ShaderIn vsIn) {
180 uint screenId = uint(vsIn.screenId);
182 uint baseIndex = screenId * 5;
184 float4 origin = ScreenInfo.Load(int3(baseIndex, 0, 0));
185 float4 XDir = ScreenInfo.Load(int3(baseIndex + 1, 0, 0));
186 float4 YDir = ScreenInfo.Load(int3(baseIndex + 2, 0, 0));
187 float4 originVertexCoord = ScreenInfo.Load(int3(baseIndex + 3, 0, 0));
188 float4 VertexCoordSize = ScreenInfo.Load(int3(baseIndex + 4, 0, 0));
190 float2 vertexCoord = vsIn.vertexcoord;
192 float3 worldPos = origin.xyz +
193 XDir.xyz * (vertexCoord.x - originVertexCoord.x) / VertexCoordSize.x +
194 YDir.xyz * (vertexCoord.y - originVertexCoord.y) / VertexCoordSize.y;
196 float4 position = float4(worldPos, 1.0);
200 std::string viewMatrixName =
m_viewMatrix.second.getName();
203 code +=
" float4 viewPos = mul(" + viewMatrixName +
", position);\n";
204 code +=
" vsOut.pos = mul(" + projMatrixName +
", viewPos);\n";
206 std::string viewMatrixName =
m_viewMatrix.second.getName();
208 code +=
" vsOut.pos = mul(" + viewMatrixName +
", position);\n";
212 code +=
" vsOut.pos = mul(" + projMatrixName +
", position);\n";
214 code +=
" vsOut.pos = position;\n";
218 vsOut.cmdoffset = vsIn.cmdoffset;
219 vsOut.cmdSize = vsIn.cmdSize;
220 vsOut.screenId = vsIn.screenId;
221 vsOut.vertexcoord = vsIn.vertexcoord;
234 code +=
"\n#define vertexOuputTarget target" + std::to_string(
m_targetIndex);
238const float VertexCommand_End = -1.0;
239const float VertexCommand_MoveTo = 1.0;
240const float VertexCommand_LineTo = 2.0;
241const float VertexCommand_BezierCurveTo = 3.0;
242const float VertexCommand_SetColor = 4.0;
243const float VertexCommand_ArcTo = 6.0;
244const float VertexCommand_SetTransform = 5.0;
245const float VertexCommand_BeginPath = 7.0;
246const float VertexCommand_EndPath = 8.0;
248int GetCurveRootFlags(float v0, float v1, float v2) {
249 int shift = ((v0 > 0.0) ? 2 : 0) + ((v1 > 0.0) ? 4 : 0) + ((v2 > 0.0) ? 8 : 0);
250 return (0x2E74 >> shift) & 0x03;
253float2 QuadCurveSolveXAxis(float2 v0, float2 v1, float2 v2) {
254 float2 a = v0 - 2.0 * v1 + v2;
257 float ra = 1.0 / a.y;
258 float rb = 0.5 / b.y;
259 float delta = sqrt(max(b.y * b.y - a.y * c, 0.0));
260 float2 t = float2((b.y - delta) * ra, (b.y + delta) * ra);
261 if (abs(a.y) < 0.0001220703125) t = float2(c * rb, c * rb);
262 return (a.x * t - b.x * 2.0) * t + v0.x;
265float2 QuadCurveSolveYAxis(float2 v0, float2 v1, float2 v2) {
266 float2 a = v0 - 2.0 * v1 + v2;
269 float ra = 1.0 / a.x;
270 float rb = 0.5 / b.x;
271 float delta = sqrt(max(b.x * b.x - a.x * c, 0.0));
272 float2 t = float2((b.x - delta) * ra, (b.x + delta) * ra);
273 if (abs(a.x) < 0.0001220703125) t = float2(c * rb, c * rb);
274 return (a.y * t - b.y * 2.0) * t + v0.y;
277float CurveTestXAxis(float2 v0, float2 v1, float2 v2, float2 pixelsPerUnit) {
278 if (max(max(v0.x, v1.x), v2.x) * pixelsPerUnit.x < -0.5) return 0.0;
279 int flags = GetCurveRootFlags(v0.y, v1.y, v2.y);
280 if (flags == 0) return 0.0;
281 float2 x1x2 = QuadCurveSolveXAxis(v0, v1, v2) * pixelsPerUnit.x;
283 if ((flags & 1) != 0) {
284 ret += clamp(x1x2.x + 0.5, 0.0, 1.0);
286 if ((flags & 2) != 0) {
287 ret -= clamp(x1x2.y + 0.5, 0.0, 1.0);
292float CurveTestYAxis(float2 v0, float2 v1, float2 v2, float2 pixelsPerUnit) {
293 if (max(max(v0.y, v1.y), v2.y) * pixelsPerUnit.y < -0.5) return 0.0;
294 int flags = GetCurveRootFlags(v0.x, v1.x, v2.x);
295 if (flags == 0) return 0.0;
296 float2 y1y2 = QuadCurveSolveYAxis(v0, v1, v2) * pixelsPerUnit.y;
298 if ((flags & 0x01) != 0) {
299 ret -= clamp(y1y2.x + 0.5, 0.0, 1.0);
301 if ((flags & 0x02) != 0) {
302 ret += clamp(y1y2.y + 0.5, 0.0, 1.0);
307float2 CurveTest(float2 v0, float2 v1, float2 v2, float2 pixelsPerUnit) {
309 CurveTestXAxis(v0, v1, v2, pixelsPerUnit),
310 CurveTestYAxis(v0, v1, v2, pixelsPerUnit)
314float2 LineTest(float2 v0, float2 v1, float2 pixelsPerUnit) {
315 float2 result = float2(0.0, 0.0);
317 if (max(v0.x, v1.x) * pixelsPerUnit.x >= -0.5) {
318 int signX = (v0.y > 0.0 ? 1 : 0) - (v1.y > 0.0 ? 1 : 0);
320 float xt = (v1.y * v0.x - v0.y * v1.x) / (v1.y - v0.y);
321 result.x = float(signX) * clamp(xt * pixelsPerUnit.x + 0.5, 0.0, 1.0);
325 if (max(v0.y, v1.y) * pixelsPerUnit.y >= -0.5) {
326 int signY = (v1.x > 0.0 ? 1 : 0) - (v0.x > 0.0 ? 1 : 0);
328 float yt = (v1.x * v0.y - v0.x * v1.y) / (v1.x - v0.x);
329 result.y = float(signY) * clamp(yt * pixelsPerUnit.y + 0.5, 0.0, 1.0);
336float2 ArcTest(float2 pos, float2 bp, float2 ep, float2 c, float b, float e, float r, float q, float2 pixelsPerUnit) {
337 float2 ret = float2(0.0, 0.0);
338 float minX = min(bp.x, ep.x);
339 float minY = min(bp.y, ep.y);
340 float maxX = max(bp.x, ep.x);
341 float maxY = max(bp.y, ep.y);
342 bool isInx = (pos.x >= minX && pos.x <= maxX);
343 bool isIny = (pos.y >= minY && pos.y <= maxY);
344 bool isInCircle = length(pos - c) <= r;
345 float bLessE = b < e ? 1.0 : -1.0;
347 if (q == 1.0 || q == 4.0) {
348 ret.x = float(isIny && (isInCircle || pos.x < minX));
351 ret.x = float(isIny && pos.x < maxX && !isInCircle);
355 if (q == 1.0 || q == 2.0) {
356 ret.y = float(isInx && (isInCircle || pos.y < minY));
359 ret.y = float(isInx && pos.y < maxY && !isInCircle);
366float NoZeroSign(float x) {
367 return x >= 0.0 ? 1.0 : -1.0;
370float2 applyTransform(float2 needTransformPoint, float3x3 transform) {
371 float3 transformedPoint = mul(float3(needTransformPoint, 1.0), transform);
372 return transformedPoint.xy / transformedPoint.z;
375float fetchCommand(int commandIndex) {
376 int pixelIndex = commandIndex / 4;
377 int channelIndex = commandIndex % 4;
379 int x = pixelIndex % 4096;
380 int y = pixelIndex / 4096;
382 float4 pixel = VertexCommandBuffer.Load(int3(x, y, 0));
384 if (channelIndex == 0) return pixel.r;
385 else if (channelIndex == 1) return pixel.g;
386 else if (channelIndex == 2) return pixel.b;
390ShaderOut main(ShaderIn ps_input) {
391 float transformSign = 1.0;
392 float3x3 transform = float3x3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0);
394 ps_output.vertexOuputTarget = float4(1.0, 1.0, 1.0, 1.0);
396 float2 unitsPerPixel = fwidth(ps_input.vertexcoord);
397 float2 pixelsPerUnit = 1.0 / unitsPerPixel;
399 float2 crossings = float2(0.0, 0.0);
401 int i = int(ps_input.cmdoffset);
403 float4 fillColor = float4(1.0, 0.647, 0.0, 1.0);
404 float4 currentColor = float4(1.0, 0.647, 0.0, 1.0);
405 bool isPathStarted = false;
406 float2 pathCrossings = float2(0.0, 0.0);
408 float pathOperation = 0.0; // 0: 默认 1:并 2:交 3:补
409 int edge = i + int(ps_input.cmdSize);
411 float command = fetchCommand(i);
413 switch (int(command)) {
414 case int(VertexCommand_BeginPath):
416 isPathStarted = true;
417 pathCrossings = float2(0.0, 0.0);
418 pathOperation = fetchCommand(i);
422 case int(VertexCommand_EndPath):
424 isPathStarted = false;
425 if (length(pathCrossings) > 0.0) {
426 fillColor = currentColor;
428 if (pathOperation == 0.0) {
429 crossings += pathCrossings;
430 } else if (pathOperation == 1.0) {
432 NoZeroSign(crossings.x) * NoZeroSign(pathCrossings.x) * max(abs(crossings.x), abs(pathCrossings.x)),
433 NoZeroSign(crossings.y) * NoZeroSign(pathCrossings.y) * max(abs(crossings.y), abs(pathCrossings.y))
435 } else if (pathOperation == 2.0) {
437 sign(crossings.x) * sign(pathCrossings.x) * min(abs(crossings.x), abs(pathCrossings.x)),
438 sign(crossings.y) * sign(pathCrossings.y) * min(abs(crossings.y), abs(pathCrossings.y))
440 } else if (pathOperation == 3.0) {
441 crossings += pathCrossings;
443 NoZeroSign(crossings.x) * (1.0 - abs(crossings.x)),
444 NoZeroSign(crossings.y) * (1.0 - abs(crossings.y))
447 pathCrossings = float2(0, 0);
451 case int(VertexCommand_MoveTo):
453 lastPos.x = fetchCommand(i);
454 lastPos.y = fetchCommand(i+1);
455 lastPos = applyTransform(lastPos, transform);
459 case int(VertexCommand_LineTo):
462 to.x = fetchCommand(i);
463 to.y = fetchCommand(i+1);
464 to = applyTransform(to, transform);
467 float2 v0 = lastPos - ps_input.vertexcoord;
468 float2 v1 = to - ps_input.vertexcoord;
469 pathCrossings += transformSign * LineTest(v0, v1, pixelsPerUnit);
473 case int(VertexCommand_SetColor):
475 currentColor.r = fetchCommand(i);
476 currentColor.g = fetchCommand(i+1);
477 currentColor.b = fetchCommand(i+2);
478 currentColor.a = fetchCommand(i+3);
482 case int(VertexCommand_ArcTo):
486 c.x = fetchCommand(i);
487 c.y = fetchCommand(i+1);
488 c = applyTransform(c, transform);
489 float r = length(c - bp);
490 float b = fetchCommand(i+2);
491 float e = fetchCommand(i+3);
492 float q = fetchCommand(i+4);
493 float2 ep = c + float2(r * cos(e), r * sin(e));
494 pathCrossings += transformSign * ArcTest(ps_input.vertexcoord, bp, ep, c, b, e, r, q, pixelsPerUnit);
499 case int(VertexCommand_BezierCurveTo):
501 float2 control = float2(fetchCommand(i),
503 float2 end = float2(fetchCommand(i+2),
505 control = applyTransform(control, transform);
506 end = applyTransform(end, transform);
509 float2 v0 = lastPos - ps_input.vertexcoord;
510 float2 v1 = control - ps_input.vertexcoord;
511 float2 v2 = end - ps_input.vertexcoord;
512 pathCrossings += transformSign * CurveTest(v0, v1, v2, pixelsPerUnit);
516 case int(VertexCommand_SetTransform):
518 transform = float3x3(
519 fetchCommand(i), fetchCommand(i+1), fetchCommand(i+2),
520 fetchCommand(i+3), fetchCommand(i+4), fetchCommand(i+5),
521 fetchCommand(i+6), fetchCommand(i+7), fetchCommand(i+8)
525 float det = determinant(transform);
526 transformSign = NoZeroSign(det);
530 if (command == VertexCommand_End) break;
533 float weightX = 1.0 - abs(crossings.x * 2.0 - 1.0);
534 float weightY = 1.0 - abs(crossings.y * 2.0 - 1.0);
535 float coverage = max(abs(crossings.x * weightX + crossings.y * weightY) / max(weightX + weightY, 0.0001220703125), min(abs(crossings.x), abs(crossings.y)));
538 ps_output.vertexOuputTarget = fillColor;
539 ps_output.vertexOuputTarget.a *= coverage;
541 //ps_output.vertexOuputTarget.r = crossings.x;
542 //ps_output.vertexOuputTarget.g = crossings.y;
543 //ps_output.vertexOuputTarget.b = 0.0;
544 //ps_output.vertexOuputTarget.a = 1.0;
constexpr const ConstElement & getElement(size_t index) const noexcept
void mvpUniformLayout(ConstLayout layout)
std::map< std::string, uint32_t > m_screenIndexMap
std::vector< PassResource * > m_passResources
static constexpr PixelLayout pixelLayout
std::pair< ConstLayout, ConstElement > m_projectionMatrix
void addRectangle(uint32_t screenId, uint32_t commandOffset, uint32_t commandSize, const Vec4 &bounds)
static constexpr const char * VertexCommandBufferNameInShder
TraditionPipelineState * m_pso
std::vector< VertexScreen > m_screens
static constexpr const char * ScreenInfoNameInShder
std::vector< VertexScreenInfo > m_infos
static constexpr VertexLayout vertexLayout
static constexpr ResourceLayout resourceLayout
VertexScreen & setScreen(const std::string &name)
DynamicMesh< uint32_t > * m_mesh
std::vector< float > m_commandBuffer
std::pair< ConstLayout, ConstElement > m_viewMatrix
void generatePixelShader()
void addScreen(const std::string &name)
void generateVertexShader()