From 46041111d8bd534aff5e8120af707fae91320356 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Thu, 16 May 2024 19:55:54 +0300 Subject: [PATCH] wg_engine: Text support [issues 1479: Text](#1479) EvenOdd fill rule reorganized: using global bbox of whole path for fill --- src/renderer/wg_engine/tvgWgRenderData.cpp | 16 ++++++++- src/renderer/wg_engine/tvgWgRenderData.h | 5 +++ src/renderer/wg_engine/tvgWgRenderTarget.cpp | 34 ++++++++++++++++++-- src/renderer/wg_engine/tvgWgRenderTarget.h | 3 +- src/renderer/wg_engine/tvgWgRenderer.cpp | 1 + 5 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index f9586cc8..ef8e0d75 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -264,10 +264,19 @@ void WgRenderDataPaint::release(WgContext& context) // WgRenderDataShape //*********************************************************************** +void WgRenderDataShape::updateBBox(WgPoint pmin, WgPoint pmax) +{ + pMin.x = std::min(pMin.x, pmin.x); + pMin.y = std::min(pMin.y, pmin.y); + pMax.x = std::max(pMax.x, pmax.x); + pMax.y = std::max(pMax.y, pmax.y); +} + + void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rshape) { releaseMeshes(context); - strokeFirst = false; + strokeFirst = rshape.stroke ? rshape.stroke->strokeFirst : false; static WgPolyline polyline; polyline.clear(); @@ -296,6 +305,7 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha } // proceed last polyline updateMeshes(context, &polyline, rshape.stroke); + meshDataBBox.update(context, pMin, pMax); } @@ -308,6 +318,7 @@ void WgRenderDataShape::updateMeshes(WgContext& context, const WgPolyline* polyl polyline->getBBox(pmin, pmax); meshGroupShapes.append(context, polyline); meshGroupShapesBBox.append(context, pmin, pmax); + updateBBox(pmin, pmax); } // generate strokes geometry if ((polyline->pts.count >= 1) && rstroke) { @@ -342,12 +353,15 @@ void WgRenderDataShape::releaseMeshes(WgContext &context) meshGroupStrokes.release(context); meshGroupShapesBBox.release(context); meshGroupShapes.release(context); + pMin = {0.0f, 0.0f }; + pMax = {0.0f, 0.0f }; } void WgRenderDataShape::release(WgContext& context) { releaseMeshes(context); + meshDataBBox.release(context); renderSettingsStroke.release(context); renderSettingsShape.release(context); WgRenderDataPaint::release(context); diff --git a/src/renderer/wg_engine/tvgWgRenderData.h b/src/renderer/wg_engine/tvgWgRenderData.h index 361be074..1329b5ab 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.h +++ b/src/renderer/wg_engine/tvgWgRenderData.h @@ -97,10 +97,15 @@ struct WgRenderDataShape: public WgRenderDataPaint WgRenderSettings renderSettingsStroke{}; WgMeshDataGroup meshGroupShapes{}; WgMeshDataGroup meshGroupShapesBBox{}; + WgMeshData meshDataBBox{}; WgMeshDataGroup meshGroupStrokes{}; WgMeshDataGroup meshGroupStrokesBBox{}; + WgPoint pMin{}; + WgPoint pMax{}; bool strokeFirst{}; + FillRule fillRule{}; + void updateBBox(WgPoint pmin, WgPoint pmax); void updateMeshes(WgContext& context, const RenderShape& rshape); void updateMeshes(WgContext& context, const WgPolyline* polyline, const RenderStroke* rstroke); void releaseMeshes(WgContext& context); diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.cpp b/src/renderer/wg_engine/tvgWgRenderTarget.cpp index f516bd66..1b41a206 100644 --- a/src/renderer/wg_engine/tvgWgRenderTarget.cpp +++ b/src/renderer/wg_engine/tvgWgRenderTarget.cpp @@ -82,9 +82,15 @@ void WgRenderStorage::renderShape(WgContext& context, WgRenderDataShape* renderD { assert(renderData); assert(mRenderPassEncoder); + // draw strokes if (renderData->strokeFirst) drawStroke(context, renderData, blendType); - drawShape(context, renderData, blendType); + // draw shape + if(renderData->fillRule == FillRule::Winding) + drawShapeWinding(context, renderData, blendType); + else if(renderData->fillRule == FillRule::EvenOdd) + drawShapeEvenOdd(context, renderData, blendType); + // draw strokes if (!renderData->strokeFirst) drawStroke(context, renderData, blendType); } @@ -101,7 +107,7 @@ void WgRenderStorage::renderPicture(WgContext& context, WgRenderDataPicture* ren } -void WgRenderStorage::drawShape(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType) +void WgRenderStorage::drawShapeWinding(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType) { assert(renderData); assert(mRenderPassEncoder); @@ -126,6 +132,30 @@ void WgRenderStorage::drawShape(WgContext& context, WgRenderDataShape* renderDat } +void WgRenderStorage::drawShapeEvenOdd(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType) +{ + assert(renderData); + assert(mRenderPassEncoder); + assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count); + // draw shape geometry + wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0); + // draw to stencil (first pass) + mPipelines->fillShape.use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint); + for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++) + renderData->meshGroupShapes.meshes[i]->drawFan(context, mRenderPassEncoder); + // fill shape geometry (second pass) + uint8_t blend = (uint8_t)blendType; + WgRenderSettings& settings = renderData->renderSettingsShape; + if (settings.fillType == WgRenderSettingsType::Solid) + mPipelines->solid[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupSolid); + else if (settings.fillType == WgRenderSettingsType::Linear) + mPipelines->linear[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupLinear); + else if (settings.fillType == WgRenderSettingsType::Radial) + mPipelines->radial[blend].use(mRenderPassEncoder, mBindGroupCanvas, renderData->bindGroupPaint, settings.bindGroupRadial); + renderData->meshDataBBox.drawFan(context, mRenderPassEncoder); +} + + void WgRenderStorage::drawStroke(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType) { assert(renderData); diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.h b/src/renderer/wg_engine/tvgWgRenderTarget.h index 2670eaa4..60e101e4 100644 --- a/src/renderer/wg_engine/tvgWgRenderTarget.h +++ b/src/renderer/wg_engine/tvgWgRenderTarget.h @@ -64,7 +64,8 @@ public: WgBindGroupOpacity* opacity); void antialias(WGPUCommandEncoder commandEncoder, WgRenderStorage* targetSrc); private: - void drawShape(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType); + void drawShapeWinding(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType); + void drawShapeEvenOdd(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType); void drawStroke(WgContext& context, WgRenderDataShape* renderData, WgPipelineBlendType blendType); void dispatchWorkgroups(WGPUComputePassEncoder computePassEncoder); diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index 408aa7a8..f50064e8 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -93,6 +93,7 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const WgShaderTypeMat4x4f modelMat(transform); WgShaderTypeBlendSettings blendSettings(mTargetSurface.cs, opacity); renderDataShape->bindGroupPaint.initialize(mContext.device, mContext.queue, modelMat, blendSettings); + renderDataShape->fillRule = rshape.rule; } // setup fill settings