mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +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
|
||||
Rafał Mikrut <mikrutrafal@protonmail.com>
|
||||
Martin Capitanio <capnm@capitanio.org>
|
||||
RuiwenTang <tangruiwen1989@gmail.com>
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
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',
|
||||
'tvgBezier.h',
|
||||
'tvgCompressor.h',
|
||||
'tvgList.h',
|
||||
'tvgMath.h',
|
||||
'tvgStr.h',
|
||||
'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