mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-10 14:41:50 +00:00
gl_engine: Use advance tessellate algorithm
Introducing a new tessellate algorithm to break polygon into triangles.
This commit is contained in:
parent
7b40c741ac
commit
7eeba75472
10 changed files with 2452 additions and 358 deletions
1
AUTHORS
1
AUTHORS
|
@ -21,3 +21,4 @@ EunSik Jeong <rinechran@outlook.jp>
|
||||||
Samsung Electronics Co., Ltd
|
Samsung Electronics Co., Ltd
|
||||||
Rafał Mikrut <mikrutrafal@protonmail.com>
|
Rafał Mikrut <mikrutrafal@protonmail.com>
|
||||||
Martin Capitanio <capnm@capitanio.org>
|
Martin Capitanio <capnm@capitanio.org>
|
||||||
|
RuiwenTang <tangruiwen1989@gmail.com>
|
||||||
|
|
|
@ -17,6 +17,8 @@ source_file = [
|
||||||
'tvgGlRenderTask.cpp',
|
'tvgGlRenderTask.cpp',
|
||||||
'tvgGlShader.cpp',
|
'tvgGlShader.cpp',
|
||||||
'tvgGlShaderSrc.cpp',
|
'tvgGlShaderSrc.cpp',
|
||||||
|
'tvgGlTessellator.cpp',
|
||||||
|
'tvgGlTessellator.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
gles_dep = meson.get_compiler('cpp').find_library('GLESv2')
|
gles_dep = meson.get_compiler('cpp').find_library('GLESv2')
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
#include "tvgGlGpuBuffer.h"
|
#include "tvgGlGpuBuffer.h"
|
||||||
#include "tvgGlGeometry.h"
|
#include "tvgGlGeometry.h"
|
||||||
|
#include "tvgGlTessellator.h"
|
||||||
|
|
||||||
#define NORMALIZED_TOP_3D 1.0f
|
#define NORMALIZED_TOP_3D 1.0f
|
||||||
#define NORMALIZED_BOTTOM_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 (flag & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) {
|
||||||
{
|
mFillVertexOffset = mStaveVertex.count * sizeof(float);
|
||||||
if (primitiveIndex >= mPrimitives.size()) return GlSize();
|
mFillIndexOffset = mStageIndex.count * sizeof(uint32_t);
|
||||||
GlSize size = mPrimitives[primitiveIndex].mBottomRight - mPrimitives[primitiveIndex].mTopLeft;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Array<float> vertex;
|
||||||
|
Array<uint32_t> index;
|
||||||
|
|
||||||
bool GlGeometry::decomposeOutline(const RenderShape& rshape)
|
tvg::Tessellator tess{&vertex, &index};
|
||||||
{
|
tess.tessellate(&rshape, true);
|
||||||
auto cmds = rshape.path.cmds.data;
|
|
||||||
auto cmdCnt = rshape.path.cmds.count;
|
|
||||||
auto pts = rshape.path.pts.data;
|
|
||||||
auto ptsCnt = rshape.path.pts.count;
|
|
||||||
|
|
||||||
//No actual shape data
|
mFillCount = index.count;
|
||||||
if (cmdCnt == 0 || ptsCnt == 0) return false;
|
|
||||||
|
|
||||||
GlPrimitive* curPrimitive = nullptr;
|
mStaveVertex.push(vertex);
|
||||||
GlPoint min = { FLT_MAX, FLT_MAX };
|
mStageIndex.push(index);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
Array<float> vertex;
|
||||||
{
|
Array<uint32_t> index;
|
||||||
for (auto& shapeGeometry : mPrimitives) {
|
|
||||||
vector<PointNormals> normalInfo;
|
|
||||||
constexpr float blurDir = -1.0f;
|
|
||||||
float antiAliasWidth = 1.0f;
|
|
||||||
vector<SmoothPoint>& aaPts = shapeGeometry.mAAPoints;
|
|
||||||
|
|
||||||
const float stroke = (strokeWd > 1) ? strokeWd - antiAliasWidth : strokeWd;
|
tvg::Stroker stroke{&vertex, &index};
|
||||||
|
stroke.stroke(&rshape);
|
||||||
|
|
||||||
size_t nPoints = aaPts.size();
|
mStrokeCount = index.count;
|
||||||
if (nPoints < 2) return false;
|
|
||||||
|
|
||||||
normalInfo.resize(nPoints);
|
mStaveVertex.push(vertex);
|
||||||
|
mStageIndex.push(index);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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)
|
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);
|
if (mVao == 0) glGenVertexArrays(1, &mVao);
|
||||||
glBindVertexArray(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(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 (mVertexBuffer == nullptr) mVertexBuffer = std::make_unique<GlGpuBuffer>();
|
||||||
if (mIndexBuffer == nullptr) mIndexBuffer = 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());
|
mVertexBuffer->updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, mStaveVertex.count * sizeof(float), mStaveVertex.data);
|
||||||
mIndexBuffer->updateBufferData(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER, vertexArray.indices.size() * sizeof(uint32_t), vertexArray.indices.data());
|
mIndexBuffer->updateBufferData(GlGpuBuffer::Target::ELEMENT_ARRAY_BUFFER, mStageIndex.count * sizeof(uint32_t), mStageIndex.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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "tvgArray.h"
|
||||||
#include "tvgGlCommon.h"
|
#include "tvgGlCommon.h"
|
||||||
|
|
||||||
#define PI 3.1415926535897932384626433832795f
|
#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 GlGpuBuffer;
|
||||||
|
|
||||||
class GlGeometry
|
class GlGeometry
|
||||||
|
@ -241,34 +189,27 @@ public:
|
||||||
|
|
||||||
~GlGeometry();
|
~GlGeometry();
|
||||||
|
|
||||||
uint32_t getPrimitiveCount();
|
bool tesselate(const RenderShape& rshape, RenderUpdateFlag flag);
|
||||||
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);
|
|
||||||
void disableVertex(uint32_t location);
|
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);
|
void updateTransform(const RenderTransform* transform, float w, float h);
|
||||||
float* getTransforMatrix();
|
float* getTransforMatrix();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addGeometryPoint(VertexDataArray &geometry, const GlPoint &pt, float viewWd, float viewHt, float opacity);
|
void updateBuffer(const uint32_t location);
|
||||||
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);
|
|
||||||
|
|
||||||
|
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;
|
GLuint mVao = 0;
|
||||||
std::unique_ptr<GlGpuBuffer> mVertexBuffer;
|
std::unique_ptr<GlGpuBuffer> mVertexBuffer;
|
||||||
std::unique_ptr<GlGpuBuffer> mIndexBuffer;
|
std::unique_ptr<GlGpuBuffer> mIndexBuffer;
|
||||||
vector<GlPrimitive> mPrimitives;
|
float mTransform[16];
|
||||||
float mTransform[16];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _TVG_GL_GEOMETRY_H_ */
|
#endif /* _TVG_GL_GEOMETRY_H_ */
|
||||||
|
|
|
@ -153,31 +153,27 @@ bool GlRenderer::renderShape(RenderData data)
|
||||||
|
|
||||||
GL_CHECK(glViewport(0, 0, (GLsizei)sdata->viewWd, (GLsizei)sdata->viewHt));
|
GL_CHECK(glViewport(0, 0, (GLsizei)sdata->viewWd, (GLsizei)sdata->viewHt));
|
||||||
|
|
||||||
uint32_t primitiveCount = sdata->geometry->getPrimitiveCount();
|
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
|
||||||
for (uint32_t i = 0; i < primitiveCount; ++i)
|
|
||||||
{
|
{
|
||||||
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
|
auto gradient = sdata->rshape->fill;
|
||||||
{
|
if (gradient) drawPrimitive(*sdata, gradient, RenderUpdateFlag::Gradient);
|
||||||
auto gradient = sdata->rshape->fill;
|
}
|
||||||
if (gradient) drawPrimitive(*sdata, gradient, i, 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);
|
drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Color);
|
||||||
if (a > 0)
|
|
||||||
{
|
|
||||||
drawPrimitive(*sdata, r, g, b, a, i, 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);
|
drawPrimitive(*sdata, r, g, b, a, RenderUpdateFlag::Stroke);
|
||||||
if (a > 0)
|
|
||||||
{
|
|
||||||
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,7 +226,6 @@ RenderData GlRenderer::prepare(const RenderShape& rshape, RenderData data, const
|
||||||
uint8_t alphaF = 0, alphaS = 0;
|
uint8_t alphaF = 0, alphaS = 0;
|
||||||
rshape.fillColor(nullptr, nullptr, nullptr, &alphaF);
|
rshape.fillColor(nullptr, nullptr, nullptr, &alphaF);
|
||||||
rshape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
|
rshape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
|
||||||
auto strokeWd = rshape.strokeWidth();
|
|
||||||
|
|
||||||
if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
|
if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
|
||||||
((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 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->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
|
||||||
{
|
{
|
||||||
if (!sdata->geometry->decomposeOutline(rshape)) return sdata;
|
if (!sdata->geometry->tesselate(rshape, sdata->updateFlag)) 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;
|
|
||||||
}
|
}
|
||||||
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());
|
GlColorRenderTask* renderTask = static_cast<GlColorRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_Color].get());
|
||||||
assert(renderTask);
|
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);
|
renderTask->setTransform(FORMAT_SIZE_MAT_4x4, matrix);
|
||||||
int32_t vertexLoc = renderTask->getLocationPropertyId();
|
int32_t vertexLoc = renderTask->getLocationPropertyId();
|
||||||
renderTask->uploadValues();
|
renderTask->uploadValues();
|
||||||
sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
|
sdata.geometry->draw(vertexLoc, flag);
|
||||||
sdata.geometry->disableVertex(vertexLoc);
|
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;
|
const Fill::ColorStop* stops = nullptr;
|
||||||
auto stopCnt = fill->colorStops(&stops);
|
auto stopCnt = fill->colorStops(&stops);
|
||||||
|
@ -386,7 +379,7 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, uint32_t primit
|
||||||
}
|
}
|
||||||
|
|
||||||
rTask->uploadValues();
|
rTask->uploadValues();
|
||||||
sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
|
sdata.geometry->draw(vertexLoc, flag);
|
||||||
sdata.geometry->disableVertex(vertexLoc);
|
sdata.geometry->disableVertex(vertexLoc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,8 +62,8 @@ private:
|
||||||
~GlRenderer();
|
~GlRenderer();
|
||||||
|
|
||||||
void initShaders();
|
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, uint8_t r, uint8_t g, uint8_t b, uint8_t a, RenderUpdateFlag flag);
|
||||||
void drawPrimitive(GlShape& sdata, const Fill* fill, uint32_t primitiveIndex, RenderUpdateFlag flag);
|
void drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFlag flag);
|
||||||
|
|
||||||
vector<shared_ptr<GlRenderTask>> mRenderTasks;
|
vector<shared_ptr<GlRenderTask>> mRenderTasks;
|
||||||
};
|
};
|
||||||
|
|
2095
src/lib/gl_engine/tvgGlTessellator.cpp
Normal file
2095
src/lib/gl_engine/tvgGlTessellator.cpp
Normal file
File diff suppressed because it is too large
Load diff
184
src/lib/gl_engine/tvgGlTessellator.h
Normal file
184
src/lib/gl_engine/tvgGlTessellator.h
Normal 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 ¢er);
|
||||||
|
|
||||||
|
void strokeMiter(const GlPoint &prev, const GlPoint &curr, const GlPoint ¢er);
|
||||||
|
|
||||||
|
void strokeBevel(const GlPoint &prev, const GlPoint &curr, const GlPoint ¢er);
|
||||||
|
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_ */
|
|
@ -2,6 +2,7 @@ source_file = [
|
||||||
'tvgArray.h',
|
'tvgArray.h',
|
||||||
'tvgBezier.h',
|
'tvgBezier.h',
|
||||||
'tvgCompressor.h',
|
'tvgCompressor.h',
|
||||||
|
'tvgList.h',
|
||||||
'tvgMath.h',
|
'tvgMath.h',
|
||||||
'tvgStr.h',
|
'tvgStr.h',
|
||||||
'tvgBezier.cpp',
|
'tvgBezier.cpp',
|
||||||
|
|
90
src/utils/tvgList.h
Normal file
90
src/utils/tvgList.h
Normal 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_
|
Loading…
Add table
Reference in a new issue