From bad02c7de04e1705924ae9bbff80c9db1c19e1ba Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Wed, 1 Nov 2023 12:06:21 +0200 Subject: [PATCH] Added ability to draw solid strokes with dashes [issues 1479: Shape](https://github.com/thorvg/thorvg/issues/1479) In order to build you need third party libraries. Before you start please read this: [LearnWebGPU](https://eliemichel.github.io/LearnWebGPU/getting-started/hello-webgpu.html) Usage example: // init glfw glfwInit(); // create a windowed mode window and its opengl context glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); GLFWwindow* window = glfwCreateWindow(800, 800, "WebGPU base app", nullptr, nullptr); // get window size int width{}, height{}; glfwGetWindowSize(window, &width, &height); // init engine webgpu tvg::Initializer::init(tvg::CanvasEngine::Wg, 0); // create wg canvas auto canvasWg = tvg::WgCanvas::gen(); canvas_wg->target(glfwGetWin32Window(window), width, height); //Test for Stroke Dash for Arc, Circle, Rect auto shape = tvg::Shape::gen(); shape->appendArc(70, 600, 160, 10, 30, true); shape->appendCircle(70, 700, 20, 60); shape->appendRect(130, 710, 100, 40); shape->strokeFill(255, 0, 0); shape->strokeWidth(5); shape->strokeJoin(tvg::StrokeJoin::Round); shape->strokeCap(tvg::StrokeCap::Round); float dashPattern[2] = {20, 10}; shape->strokeDash(dashPattern, 2); if (canvas_wg->push(std::move(shape)) != tvg::Result::Success) return; while (!glfwWindowShouldClose(window)) { // webgpu canvas_wg->draw(); canvas_wg->sync(); // pull events glfwPollEvents(); } // terminate engine and window tvg::Initializer::term(tvg::CanvasEngine::Wg); glfwDestroyWindow(window); glfwTerminate(); --- src/renderer/wg_engine/tvgWgRenderData.cpp | 46 +++++++++++++++++++++- src/renderer/wg_engine/tvgWgRenderData.h | 1 + 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index 0aa34158..1b451252 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -184,7 +184,14 @@ void WgRenderDataShape::stroke(WGPUDevice device, WGPUQueue queue, const RenderS decodePath(rshape, outlines); WgVertexList strokes; - strokeSublines(rshape, outlines, strokes); + if (rshape.stroke->dashPattern) { + Array segments; + strokeSegments(rshape, outlines, segments); + strokeSublines(rshape, segments, strokes); + for (uint32_t i = 0; i < segments.count; i++) + delete segments[i]; + } else + strokeSublines(rshape, outlines, strokes); // append shape if it can create at least one triangle // TODO: create single geometry data for strokes pere shape @@ -230,6 +237,43 @@ void WgRenderDataShape::decodePath(const RenderShape& rshape, Array& outlines, Array& segments) { + for (uint32_t i = 0; i < outlines.count; i++) { + auto& vlist = outlines[i]->mVertexList; + + // append single point segment + if (vlist.count == 1) { + auto segment = new WgVertexList(); + segment->mVertexList.push(vlist.last()); + segments.push(segment); + } + + if (vlist.count >= 2) { + uint32_t icurr = 1; + uint32_t ipatt = 0; + WgPoint vcurr = vlist[0]; + while (icurr < vlist.count) { + if (ipatt % 2 == 0) { + segments.push(new WgVertexList()); + segments.last()->mVertexList.push(vcurr); + } + float lcurr = rshape.stroke->dashPattern[ipatt]; + while ((icurr < vlist.count) && (vlist[icurr].dist(vcurr) < lcurr)) { + lcurr -= vlist[icurr].dist(vcurr); + vcurr = vlist[icurr]; + icurr++; + if (ipatt % 2 == 0) segments.last()->mVertexList.push(vcurr); + } + if (icurr < vlist.count) { + vcurr = vcurr + (vlist[icurr] - vlist[icurr-1]).normal() * lcurr; + if (ipatt % 2 == 0) segments.last()->mVertexList.push(vcurr); + } + ipatt = (ipatt + 1) % rshape.stroke->dashCnt; + } + } + } +} + void WgRenderDataShape::strokeSublines(const RenderShape& rshape, Array& outlines, WgVertexList& strokes) { float wdt = rshape.stroke->width / 2; for (uint32_t i = 0; i < outlines.count; i++) { diff --git a/src/renderer/wg_engine/tvgWgRenderData.h b/src/renderer/wg_engine/tvgWgRenderData.h index 2c125246..0066c4cd 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.h +++ b/src/renderer/wg_engine/tvgWgRenderData.h @@ -83,6 +83,7 @@ public: void stroke(WGPUDevice device, WGPUQueue queue, const RenderShape& rshape); private: void decodePath(const RenderShape& rshape, Array& outlines); + void strokeSegments(const RenderShape& rshape, Array& outlines, Array& segments); void strokeSublines(const RenderShape& rshape, Array& outlines, WgVertexList& strokes); };