wg_engine: Text support

[issues 1479: Text](#1479)

EvenOdd fill rule reorganized: using global bbox of whole path for fill
This commit is contained in:
Sergii Liebodkin 2024-05-16 19:55:54 +03:00 committed by Hermet Park
parent 7581b08c69
commit 46041111d8
5 changed files with 55 additions and 4 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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