gl_engine: Use advance tessellate algorithm

Introducing a new tessellate algorithm to break polygon into triangles.
This commit is contained in:
RuiwenTang 2023-08-18 10:33:01 +08:00 committed by Hermet Park
parent 7b40c741ac
commit 7eeba75472
10 changed files with 2452 additions and 358 deletions

View file

@ -21,3 +21,4 @@ EunSik Jeong <rinechran@outlook.jp>
Samsung Electronics Co., Ltd
Rafał Mikrut <mikrutrafal@protonmail.com>
Martin Capitanio <capnm@capitanio.org>
RuiwenTang <tangruiwen1989@gmail.com>

View file

@ -17,6 +17,8 @@ source_file = [
'tvgGlRenderTask.cpp',
'tvgGlShader.cpp',
'tvgGlShaderSrc.cpp',
'tvgGlTessellator.cpp',
'tvgGlTessellator.h',
]
gles_dep = meson.get_compiler('cpp').find_library('GLESv2')

View file

@ -23,6 +23,7 @@
#include <float.h>
#include "tvgGlGpuBuffer.h"
#include "tvgGlGeometry.h"
#include "tvgGlTessellator.h"
#define NORMALIZED_TOP_3D 1.0f
#define NORMALIZED_BOTTOM_3D -1.0f
@ -36,187 +37,53 @@ GlGeometry::~GlGeometry()
}
}
uint32_t GlGeometry::getPrimitiveCount()
bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag)
{
return mPrimitives.size();
}
mFillVertexOffset = 0;
mStrokeVertexOffset = 0;
mFillIndexOffset = 0;
mStrokeIndexOffset = 0;
mFillCount = 0;
mStrokeCount = 0;
mStaveVertex.clear();
mStageIndex.clear();
const GlSize GlGeometry::getPrimitiveSize(const uint32_t primitiveIndex) const
{
if (primitiveIndex >= mPrimitives.size()) return GlSize();
GlSize size = mPrimitives[primitiveIndex].mBottomRight - mPrimitives[primitiveIndex].mTopLeft;
return size;
}
if (flag & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) {
mFillVertexOffset = mStaveVertex.count * sizeof(float);
mFillIndexOffset = mStageIndex.count * sizeof(uint32_t);
Array<float> vertex;
Array<uint32_t> index;
bool GlGeometry::decomposeOutline(const RenderShape& rshape)
{
auto cmds = rshape.path.cmds.data;
auto cmdCnt = rshape.path.cmds.count;
auto pts = rshape.path.pts.data;
auto ptsCnt = rshape.path.pts.count;
tvg::Tessellator tess{&vertex, &index};
tess.tessellate(&rshape, true);
//No actual shape data
if (cmdCnt == 0 || ptsCnt == 0) return false;
mFillCount = index.count;
GlPrimitive* curPrimitive = nullptr;
GlPoint min = { FLT_MAX, FLT_MAX };
GlPoint max = { 0.0f, 0.0f };
for (unsigned i = 0; i < cmdCnt; ++i) {
switch (*(cmds + i)) {
case PathCommand::Close: {
if (curPrimitive) {
if (curPrimitive->mAAPoints.size() > 0 && (curPrimitive->mAAPoints[0].orgPt != curPrimitive->mAAPoints.back().orgPt)) {
curPrimitive->mAAPoints.push_back(curPrimitive->mAAPoints[0].orgPt);
}
curPrimitive->mIsClosed = true;
}
break;
}
case PathCommand::MoveTo: {
if (curPrimitive) {
curPrimitive->mTopLeft = min;
curPrimitive->mBottomRight = max;
if (curPrimitive->mAAPoints.size() > 2 && (curPrimitive->mAAPoints[0].orgPt == curPrimitive->mAAPoints.back().orgPt)) {
curPrimitive->mIsClosed = true;
}
}
mPrimitives.push_back(GlPrimitive());
curPrimitive = &mPrimitives.back();
}
TVG_FALLTHROUGH
case PathCommand::LineTo: {
if (curPrimitive) addPoint(*curPrimitive, pts[0], min, max);
pts++;
break;
}
case PathCommand::CubicTo: {
if (curPrimitive) decomposeCubicCurve(*curPrimitive, curPrimitive->mAAPoints.back().orgPt, pts[0], pts[1], pts[2], min, max);
pts += 3;
break;
}
}
}
if (curPrimitive) {
curPrimitive->mTopLeft = min;
curPrimitive->mBottomRight = max;
mStaveVertex.push(vertex);
mStageIndex.push(index);
}
return true;
}
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
mStrokeVertexOffset = mStaveVertex.count * sizeof(float);
mStrokeIndexOffset = mStageIndex.count * sizeof(uint32_t);
bool GlGeometry::generateAAPoints(TVG_UNUSED const RenderShape& rshape, float strokeWd, RenderUpdateFlag flag)
{
for (auto& shapeGeometry : mPrimitives) {
vector<PointNormals> normalInfo;
constexpr float blurDir = -1.0f;
float antiAliasWidth = 1.0f;
vector<SmoothPoint>& aaPts = shapeGeometry.mAAPoints;
Array<float> vertex;
Array<uint32_t> index;
const float stroke = (strokeWd > 1) ? strokeWd - antiAliasWidth : strokeWd;
tvg::Stroker stroke{&vertex, &index};
stroke.stroke(&rshape);
size_t nPoints = aaPts.size();
if (nPoints < 2) return false;
mStrokeCount = index.count;
normalInfo.resize(nPoints);
size_t fPoint = 0;
size_t sPoint = 1;
for (size_t i = 0; i < nPoints - 1; ++i) {
fPoint = i;
sPoint = i + 1;
if (shapeGeometry.mIsClosed && sPoint == nPoints - 1) sPoint = 0;
GlPoint normal = getNormal(aaPts[fPoint].orgPt, aaPts[sPoint].orgPt);
normalInfo[fPoint].normal1 = normal;
normalInfo[sPoint].normal2 = normal;
}
if (shapeGeometry.mIsClosed) {
normalInfo[nPoints - 1].normal1 = normalInfo[0].normal1;
normalInfo[nPoints - 1].normal2 = normalInfo[0].normal2;
} else {
normalInfo[nPoints - 1].normal1 = normalInfo[nPoints - 1].normal2;
normalInfo[0].normal2 = normalInfo[0].normal1;
}
for (uint32_t i = 0; i < nPoints; ++i) {
normalInfo[i].normalF = normalInfo[i].normal1 + normalInfo[i].normal2;
normalInfo[i].normalF.normalize();
auto angle = dotProduct(normalInfo[i].normal2, normalInfo[i].normalF);
if (angle != 0) normalInfo[i].normalF = normalInfo[i].normalF / angle;
else normalInfo[i].normalF = GlPoint(0, 0);
if (flag & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) {
aaPts[i].fillOuterBlur = extendEdge(aaPts[i].orgPt, normalInfo[i].normalF, blurDir * stroke);
aaPts[i].fillOuter = extendEdge(aaPts[i].fillOuterBlur, normalInfo[i].normalF, blurDir*antiAliasWidth);
}
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
aaPts[i].strokeOuterBlur = aaPts[i].orgPt;
aaPts[i].strokeOuter = extendEdge(aaPts[i].strokeOuterBlur, normalInfo[i].normalF, blurDir*antiAliasWidth);
aaPts[i].strokeInner = extendEdge(aaPts[i].strokeOuter, normalInfo[i].normalF, blurDir * stroke);
aaPts[i].strokeInnerBlur = extendEdge(aaPts[i].strokeInner, normalInfo[i].normalF, blurDir*antiAliasWidth);
}
}
mStaveVertex.push(vertex);
mStageIndex.push(index);
}
return true;
}
bool GlGeometry::tesselate(TVG_UNUSED const RenderShape& rshape, float viewWd, float viewHt, RenderUpdateFlag flag)
{
for (auto& shapeGeometry : mPrimitives) {
constexpr float opaque = 1.0f;
constexpr float transparent = 0.0f;
vector<SmoothPoint>& aaPts = shapeGeometry.mAAPoints;
VertexDataArray& fill = shapeGeometry.mFill;
VertexDataArray& stroke = shapeGeometry.mStroke;
if (flag & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) {
uint32_t i = 0;
for (size_t pt = 0; pt < aaPts.size(); ++pt) {
addGeometryPoint(fill, aaPts[pt].fillOuter, viewWd, viewHt, opaque);
if (i > 1) addTriangleFanIndices(i, fill.indices);
++i;
}
for (size_t pt = 1; pt < aaPts.size(); ++pt) {
addGeometryPoint(fill, aaPts[pt - 1].fillOuterBlur, viewWd, viewHt, transparent);
addGeometryPoint(fill, aaPts[pt - 1].fillOuter, viewWd, viewHt, opaque);
addGeometryPoint(fill, aaPts[pt].fillOuterBlur, viewWd, viewHt, transparent);
addGeometryPoint(fill, aaPts[pt].fillOuter, viewWd, viewHt, opaque);
addQuadIndices(i, fill.indices);
}
}
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
uint32_t i = 0;
for (size_t pt = 1; pt < aaPts.size(); ++pt) {
addGeometryPoint(stroke, aaPts[pt - 1].strokeOuter, viewWd, viewHt, opaque);
addGeometryPoint(stroke, aaPts[pt - 1].strokeInner, viewWd, viewHt, opaque);
addGeometryPoint(stroke, aaPts[pt].strokeOuter, viewWd, viewHt, opaque);
addGeometryPoint(stroke, aaPts[pt].strokeInner, viewWd, viewHt, opaque);
addQuadIndices(i, stroke.indices);
}
for (size_t pt = 1; pt < aaPts.size(); ++pt) {
addGeometryPoint(stroke, aaPts[pt - 1].strokeOuterBlur, viewWd, viewHt, transparent);
addGeometryPoint(stroke, aaPts[pt - 1].strokeOuter, viewWd, viewHt, opaque);
addGeometryPoint(stroke, aaPts[pt].strokeOuterBlur, viewWd, viewHt, transparent);
addGeometryPoint(stroke, aaPts[pt].strokeOuter, viewWd, viewHt, opaque);
addQuadIndices(i, stroke.indices);
}
for (size_t pt = 1; pt < aaPts.size(); ++pt) {
addGeometryPoint(stroke, aaPts[pt - 1].strokeInner, viewWd, viewHt, opaque);
addGeometryPoint(stroke, aaPts[pt - 1].strokeInnerBlur, viewWd, viewHt, transparent);
addGeometryPoint(stroke, aaPts[pt].strokeInner, viewWd, viewHt, opaque);
addGeometryPoint(stroke, aaPts[pt].strokeInnerBlur, viewWd, viewHt, transparent);
addQuadIndices(i, stroke.indices);
}
}
aaPts.clear();
}
return true;
}
void GlGeometry::disableVertex(uint32_t location)
{
@ -226,116 +93,36 @@ void GlGeometry::disableVertex(uint32_t location)
}
void GlGeometry::draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag)
void GlGeometry::draw(const uint32_t location, RenderUpdateFlag flag)
{
if (primitiveIndex >= mPrimitives.size()) return;
if (flag == RenderUpdateFlag::None) {
return;
}
if (mVao == 0) glGenVertexArrays(1, &mVao);
glBindVertexArray(mVao);
VertexDataArray& geometry = (flag == RenderUpdateFlag::Stroke) ? mPrimitives[primitiveIndex].mStroke : mPrimitives[primitiveIndex].mFill;
updateBuffer(location);
updateBuffer(location, geometry);
uint32_t vertexOffset = (flag == RenderUpdateFlag::Stroke) ? mStrokeVertexOffset : mFillVertexOffset;
uint32_t indexOffset = (flag == RenderUpdateFlag::Stroke) ? mStrokeIndexOffset : mFillIndexOffset;
uint32_t count = (flag == RenderUpdateFlag::Stroke) ? mStrokeCount : mFillCount;
GL_CHECK(glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), 0));
GL_CHECK(glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), reinterpret_cast<void*>(vertexOffset)));
GL_CHECK(glEnableVertexAttribArray(location));
GL_CHECK(glDrawElements(GL_TRIANGLES, geometry.indices.size(), GL_UNSIGNED_INT, 0));
GL_CHECK(glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, reinterpret_cast<void*>(indexOffset)));
}
void GlGeometry::updateBuffer(uint32_t location, const VertexDataArray& vertexArray)
void GlGeometry::updateBuffer(uint32_t location)
{
if (mVertexBuffer == nullptr) mVertexBuffer = std::make_unique<GlGpuBuffer>();
if (mIndexBuffer == nullptr) mIndexBuffer = std::make_unique<GlGpuBuffer>();
mVertexBuffer->updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, vertexArray.vertices.size() * sizeof(VertexData), vertexArray.vertices.data());
mIndexBuffer->updateBufferData(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER, vertexArray.indices.size() * sizeof(uint32_t), vertexArray.indices.data());
}
void GlGeometry::addGeometryPoint(VertexDataArray& geometry, const GlPoint &pt, float viewWd, float viewHt, float opacity)
{
VertexData tv = {pt, opacity};
geometry.vertices.push_back(tv);
}
GlPoint GlGeometry::getNormal(const GlPoint& p1, const GlPoint& p2)
{
GlPoint normal = p1 - p2;
normal.normalize();
return GlPoint(-normal.y, normal.x);
}
float GlGeometry::dotProduct(const GlPoint& p1, const GlPoint& p2)
{
return (p1.x * p2.x + p1.y * p2.y);
}
GlPoint GlGeometry::extendEdge(const GlPoint& pt, const GlPoint& normal, float scalar)
{
GlPoint tmp = (normal * scalar);
return (pt + tmp);
}
void GlGeometry::addPoint(GlPrimitive& primitve, const GlPoint& pt, GlPoint& min, GlPoint& max)
{
if (pt.x < min.x) min.x = pt.x;
if (pt.y < min.y) min.y = pt.y;
if (pt.x > max.x) max.x = pt.x;
if (pt.y > max.y) max.y = pt.y;
primitve.mAAPoints.push_back(GlPoint(pt.x, pt.y));
}
void GlGeometry::addTriangleFanIndices(uint32_t& curPt, vector<uint32_t>& indices)
{
indices.push_back(0);
indices.push_back(curPt - 1);
indices.push_back(curPt);
}
void GlGeometry::addQuadIndices(uint32_t& curPt, vector<uint32_t>& indices)
{
indices.push_back(curPt);
indices.push_back(curPt + 1);
indices.push_back(curPt + 2);
indices.push_back(curPt + 1);
indices.push_back(curPt + 3);
indices.push_back(curPt + 2);
curPt += 4;
}
bool GlGeometry::isBezierFlat(const GlPoint& p1, const GlPoint& c1, const GlPoint& c2, const GlPoint& p2)
{
GlPoint diff1 = (c1 * 3.0f) - (p1 * 2.0f) - p2;
GlPoint diff2 = (c2 * 3.0f) - (p2 * 2.0f) - p1;
diff1.mod();
diff2.mod();
if (diff1.x < diff2.x) diff1.x = diff2.x;
if (diff1.y < diff2.y) diff1.y = diff2.y;
if (diff1.x + diff1.y <= 0.5f) return true;
return false;
}
void GlGeometry::decomposeCubicCurve(GlPrimitive& primitve, const GlPoint& pt1, const GlPoint& cpt1, const GlPoint& cpt2, const GlPoint& pt2, GlPoint& min, GlPoint& max)
{
if (isBezierFlat(pt1, cpt1, cpt2, pt2)) {
addPoint(primitve, pt2, min, max);
return;
}
GlPoint p12 = (pt1 + cpt1) * 0.5f;
GlPoint p23 = (cpt1 + cpt2) * 0.5f;
GlPoint p34 = (cpt2 + pt2) * 0.5f;
GlPoint p123 = (p12 + p23) * 0.5f;
GlPoint p234 = (p23 + p34) * 0.5f;
GlPoint p1234 = (p123 + p234) * 0.5f;
decomposeCubicCurve(primitve, pt1, p12, p123, p1234, min, max);
decomposeCubicCurve(primitve, p1234, p234, p34, pt2, min, max);
mVertexBuffer->updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, mStaveVertex.count * sizeof(float), mStaveVertex.data);
mIndexBuffer->updateBufferData(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER, mStageIndex.count * sizeof(uint32_t), mStageIndex.data);
}

View file

@ -25,6 +25,7 @@
#include <math.h>
#include <vector>
#include "tvgArray.h"
#include "tvgGlCommon.h"
#define PI 3.1415926535897932384626433832795f
@ -180,59 +181,6 @@ public:
}
};
typedef GlPoint GlSize;
struct SmoothPoint
{
GlPoint orgPt;
GlPoint fillOuterBlur;
GlPoint fillOuter;
GlPoint strokeOuterBlur;
GlPoint strokeOuter;
GlPoint strokeInnerBlur;
GlPoint strokeInner;
SmoothPoint(GlPoint pt)
:orgPt(pt),
fillOuterBlur(pt),
fillOuter(pt),
strokeOuterBlur(pt),
strokeOuter(pt),
strokeInnerBlur(pt),
strokeInner(pt)
{
}
};
struct PointNormals
{
GlPoint normal1;
GlPoint normal2;
GlPoint normalF;
};
struct VertexData
{
GlPoint point;
float opacity = 0.0f;
};
struct VertexDataArray
{
vector<VertexData> vertices;
vector<uint32_t> indices;
};
struct GlPrimitive
{
vector<SmoothPoint> mAAPoints;
VertexDataArray mFill;
VertexDataArray mStroke;
GlPoint mTopLeft;
GlPoint mBottomRight;
bool mIsClosed = false;
};
class GlGpuBuffer;
class GlGeometry
@ -241,34 +189,27 @@ public:
~GlGeometry();
uint32_t getPrimitiveCount();
const GlSize getPrimitiveSize(const uint32_t primitiveIndex) const;
bool decomposeOutline(const RenderShape& rshape);
bool generateAAPoints(TVG_UNUSED const RenderShape& rshape, float strokeWd, RenderUpdateFlag flag);
bool tesselate(TVG_UNUSED const RenderShape& rshape, float viewWd, float viewHt, RenderUpdateFlag flag);
bool tesselate(const RenderShape& rshape, RenderUpdateFlag flag);
void disableVertex(uint32_t location);
void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag);
void draw(const uint32_t location, RenderUpdateFlag flag);
void updateTransform(const RenderTransform* transform, float w, float h);
float* getTransforMatrix();
private:
void addGeometryPoint(VertexDataArray &geometry, const GlPoint &pt, float viewWd, float viewHt, float opacity);
GlPoint getNormal(const GlPoint &p1, const GlPoint &p2);
float dotProduct(const GlPoint &p1, const GlPoint &p2);
GlPoint extendEdge(const GlPoint &pt, const GlPoint &normal, float scalar);
void addPoint(GlPrimitive& primitve, const GlPoint &pt, GlPoint &min, GlPoint &max);
void addTriangleFanIndices(uint32_t &curPt, vector<uint32_t> &indices);
void addQuadIndices(uint32_t &curPt, vector<uint32_t> &indices);
bool isBezierFlat(const GlPoint &p1, const GlPoint &c1, const GlPoint &c2, const GlPoint &p2);
void decomposeCubicCurve(GlPrimitive& primitve, const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2, GlPoint &min, GlPoint &max);
void updateBuffer(const uint32_t location, const VertexDataArray& vertexArray);
void updateBuffer(const uint32_t location);
Array<float> mStaveVertex;
Array<uint32_t> mStageIndex;
uint32_t mFillVertexOffset;
uint32_t mFillIndexOffset;
uint32_t mFillCount;
uint32_t mStrokeVertexOffset;
uint32_t mStrokeIndexOffset;
uint32_t mStrokeCount;
GLuint mVao = 0;
std::unique_ptr<GlGpuBuffer> mVertexBuffer;
std::unique_ptr<GlGpuBuffer> mIndexBuffer;
vector<GlPrimitive> mPrimitives;
float mTransform[16];
float mTransform[16];
};
#endif /* _TVG_GL_GEOMETRY_H_ */

View file

@ -153,31 +153,27 @@ bool GlRenderer::renderShape(RenderData data)
GL_CHECK(glViewport(0, 0, (GLsizei)sdata->viewWd, (GLsizei)sdata->viewHt));
uint32_t primitiveCount = sdata->geometry->getPrimitiveCount();
for (uint32_t i = 0; i < primitiveCount; ++i)
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
{
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
{
auto gradient = sdata->rshape->fill;
if (gradient) drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
}
auto gradient = sdata->rshape->fill;
if (gradient) drawPrimitive(*sdata, gradient, RenderUpdateFlag::Gradient);
}
if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform))
if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform))
{
sdata->rshape->fillColor(&r, &g, &b, &a);
if (a > 0)
{
sdata->rshape->fillColor(&r, &g, &b, &a);
if (a > 0)
{
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
}
drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Color);
}
}
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
{
sdata->rshape->strokeColor(&r, &g, &b, &a);
if (a > 0)
{
sdata->rshape->strokeColor(&r, &g, &b, &a);
if (a > 0)
{
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
}
drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Stroke);
}
}
@ -230,7 +226,6 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const
uint8_t alphaF = 0, alphaS = 0;
rshape.fillColor(nullptr, nullptr, nullptr, &alphaF);
rshape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
auto strokeWd = rshape.strokeWidth();
if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 0) &&
@ -243,9 +238,7 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const
if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
{
if (!sdata->geometry->decomposeOutline(rshape)) return sdata;
if (!sdata->geometry->generateAAPoints(rshape, static_cast<float>(strokeWd), sdata->updateFlag)) return sdata;
if (!sdata->geometry->tesselate(rshape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata;
if (!sdata->geometry->tesselate(rshape, sdata->updateFlag)) return sdata;
}
return sdata;
}
@ -321,7 +314,7 @@ void GlRenderer::initShaders()
}
void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint32_t primitiveIndex, RenderUpdateFlag flag)
void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag)
{
GlColorRenderTask* renderTask = static_cast<GlColorRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_Color].get());
assert(renderTask);
@ -332,13 +325,13 @@ void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b,
renderTask->setTransform(FORMAT_SIZE_MAT_4x4, matrix);
int32_t vertexLoc = renderTask->getLocationPropertyId();
renderTask->uploadValues();
sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
sdata.geometry->draw(vertexLoc, flag);
sdata.geometry->disableVertex(vertexLoc);
}
void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, uint32_t primitiveIndex, RenderUpdateFlag flag)
void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag)
{
const Fill::ColorStop* stops = nullptr;
auto stopCnt = fill->colorStops(&stops);
@ -386,7 +379,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, uint32_t primit
}
rTask->uploadValues();
sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
sdata.geometry->draw(vertexLoc, flag);
sdata.geometry->disableVertex(vertexLoc);
}
}

View file

@ -62,8 +62,8 @@ private:
~GlRenderer();
void initShaders();
void drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint32_t primitiveIndex, RenderUpdateFlag flag);
void drawPrimitive(GlShape& sdata, const Fill* fill, uint32_t primitiveIndex, RenderUpdateFlag flag);
void drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag);
void drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag);
vector<shared_ptr<GlRenderTask>> mRenderTasks;
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,184 @@
/*
* Copyright (c) 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_GL_TESSELLATOR_H_
#define _TVG_GL_TESSELLATOR_H_
#include <cstdint>
#include "tvgCommon.h"
#include "tvgArray.h"
#include "tvgBezier.h"
#include "tvgGlGeometry.h"
namespace tvg
{
namespace detail
{
class ObjectHeap;
struct Vertex;
struct Edge;
struct Polygon;
struct MonotonePolygon;
struct VertexList;
struct ActiveEdgeList;
} // namespace detail
struct RenderShape;
class Tessellator final
{
public:
Tessellator(Array<float>* points, Array<uint32_t>* indices);
~Tessellator();
void tessellate(const RenderShape *rshape, bool antialias = false);
void tessellate(const Array<const RenderShape*> &shapes);
private:
void visitShape(const PathCommand *cmds, uint32_t cmd_count, const Point *pts, uint32_t pts_count);
void buildMesh();
void mergeVertices();
void simplifyMesh();
void tessMesh();
bool matchFillRule(int32_t winding);
detail::Edge *makeEdge(detail::Vertex* p1, detail::Vertex* p2);
bool checkIntersection(detail::Edge* left, detail::Edge* right, detail::ActiveEdgeList* ael,
detail::Vertex** current);
bool splitEdge(detail::Edge* edge, detail::Vertex* v, detail::ActiveEdgeList* ael, detail::Vertex** current);
bool intersectPairEdge(detail::Edge* left, detail::Edge* right, detail::ActiveEdgeList* ael,
detail::Vertex** current);
detail::Polygon *makePoly(detail::Vertex* v, int32_t winding);
void emitPoly(detail::MonotonePolygon* poly);
void emitTriangle(detail::Vertex* p1, detail::Vertex* p2, detail::Vertex* p3);
private:
FillRule fillRule = FillRule::Winding;
std::unique_ptr<detail::ObjectHeap> pHeap;
Array<detail::VertexList*> outlines;
detail::VertexList* pMesh;
detail::Polygon* pPolygon;
Array<float>* resGlPoints;
Array<uint32_t>* resIndices;
};
class Stroker final
{
struct State
{
GlPoint firstPt = {};
GlPoint firstPtDir = {};
GlPoint prevPt = {};
GlPoint prevPtDir = {};
bool hasMove = false;
};
public:
Stroker(Array<float>* points, Array<uint32_t>* indices);
~Stroker() = default;
void stroke(const RenderShape *rshape);
private:
void doStroke(const PathCommand* cmds, uint32_t cmd_count, const Point* pts, uint32_t pts_count);
void doDashStroke(const PathCommand* cmds, uint32_t cmd_count, const Point* pts, uint32_t pts_count,
uint32_t dash_count, const float* dash_pattern);
float strokeRadius() const
{
return mStrokeWidth * 0.5f;
}
void strokeCap();
void strokeLineTo(const GlPoint &curr);
void strokeCubicTo(const GlPoint &cnt1, const GlPoint &cnt2, const GlPoint &end);
void strokeClose();
void strokeJoin(const GlPoint &dir);
void strokeRound(const GlPoint &prev, const GlPoint &curr, const GlPoint &center);
void strokeMiter(const GlPoint &prev, const GlPoint &curr, const GlPoint &center);
void strokeBevel(const GlPoint &prev, const GlPoint &curr, const GlPoint &center);
private:
Array<float>* mResGlPoints;
Array<uint32_t>* mResIndices;
float mStrokeWidth = 1.f;
float mMiterLimit = 4.f;
StrokeCap mStrokeCap = StrokeCap::Square;
StrokeJoin mStrokeJoin = StrokeJoin::Bevel;
State mStrokeState = {};
};
class DashStroke
{
public:
DashStroke(Array<PathCommand>* cmds, Array<Point>* pts, uint32_t dash_count, const float* dash_pattern);
~DashStroke() = default;
void doStroke(const PathCommand* cmds, uint32_t cmd_count, const Point* pts, uint32_t pts_count);
private:
void dashLineTo(const GlPoint &pt);
void dashCubicTo(const GlPoint &pt1, const GlPoint &pt2, const GlPoint &pt3);
void moveTo(const GlPoint &pt);
void lineTo(const GlPoint &pt);
void cubicTo(const GlPoint &pt1, const GlPoint &pt2, const GlPoint &pt3);
private:
Array<PathCommand>* mCmds;
Array<Point>* mPts;
uint32_t mDashCount;
const float* mDashPattern;
float mCurrLen;
int32_t mCurrIdx;
bool mCurOpGap;
GlPoint mPtStart;
GlPoint mPtCur;
};
} // namespace tvg
#endif /* _TVG_GL_TESSELLATOR_H_ */

View file

@ -2,6 +2,7 @@ source_file = [
'tvgArray.h',
'tvgBezier.h',
'tvgCompressor.h',
'tvgList.h',
'tvgMath.h',
'tvgStr.h',
'tvgBezier.cpp',

90
src/utils/tvgList.h Normal file
View file

@ -0,0 +1,90 @@
/*
* Copyright (c) 2023 the ThorVG project. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _TVG_LIST_H_
#define _TVG_LIST_H_
namespace tvg {
template<typename T>
struct LinkedList
{
T *head = nullptr;
T *tail = nullptr;
LinkedList() = default;
LinkedList(T *head, T *tail) : head(head), tail(tail)
{
}
template<T *T::*Prev, T *T::*Next>
static void insert(T *t, T *prev, T *next, T **head, T **tail)
{
t->*Prev = prev;
t->*Next = next;
if (prev) {
prev->*Next = t;
} else if (head) {
*head = t;
}
if (next) {
next->*Prev = t;
} else if (tail) {
*tail = t;
}
}
template<T *T::*Prev, T *T::*Next>
static void remove(T *t, T **head, T **tail)
{
if (t->*Prev) {
t->*Prev->*Next = t->*Next;
} else if (head) {
*head = t->*Next;
}
if (t->*Next) {
t->*Next->*Prev = t->*Prev;
} else if (tail) {
*tail = t->*Prev;
}
t->*Prev = t->*Next = nullptr;
}
template <T* T::*Next>
static bool contains(T *t, T **head, T **tail) {
for (T *it = *head; it; it = it->*Next) {
if (it == t) {
return true;
}
}
return false;
}
};
}
#endif // _TVG_LIST_H_