testGradientTransform
testSvg
testSvg2
+testGlShape
'tvgGlProgram.h',
'tvgGlRenderer.h',
'tvgGlShader.h',
+ 'tvgGlShaderSrc.h',
+ 'tvgGlGeometry.cpp',
+ 'tvgGlGpuBuffer.cpp',
+ 'tvgGlProgram.cpp',
'tvgGlRenderer.cpp',
+ 'tvgGlShader.cpp',
+ 'tvgGlShaderSrc.cpp',
]
glraster_dep = declare_dependency(
#define _TVG_GL_COMMON_H_\r
\r
#include "tvgCommon.h"\r
-#include "tvgGlProgram.h"\r
-#include "tvgGlShader.h"\r
-#include "tvgGlGeometry.h"\r
\r
\r
+#define GL_CHECK(x) \\r
+ x; \\r
+ do { \\r
+ GLenum glError = glGetError(); \\r
+ if(glError != GL_NO_ERROR) { \\r
+ printf("glGetError() = %i (0x%.8x) at line %s : %i\n", glError, glError, __FILE__, __LINE__); \\r
+ assert(0); \\r
+ } \\r
+ } while(0)\r
+\r
+#define EGL_CHECK(x) \\r
+ x; \\r
+ do { \\r
+ EGLint eglError = eglGetError(); \\r
+ if(eglError != EGL_SUCCESS) { \\r
+ printf("eglGetError() = %i (0x%.8x) at line %s : %i\n", eglError, eglError, __FILE__, __LINE__); \\r
+ assert(0); \\r
+ } \\r
+ } while(0)\r
+\r
+\r
+class GlGeometry;\r
+\r
struct GlShape\r
{\r
float viewWd;\r
--- /dev/null
+#include "tvgGlGpuBuffer.h"
+#include "tvgGlGeometry.h"
+#include "tvgGlCommon.h"
+
+#include <GLES2/gl2.h>
+
+
+uint32_t GlGeometry::getPrimitiveCount()
+{
+ return mPrimitives.size();
+}
+
+
+bool GlGeometry::decomposeOutline(const Shape &shape)
+{
+ const PathCommand *cmds = nullptr;
+ auto cmdCnt = shape.pathCommands(&cmds);
+
+ Point *pts = nullptr;
+ auto ptsCnt = shape.pathCoords(const_cast<const Point**>(&pts));
+
+ //No actual shape data
+ if (cmdCnt == 0 || ptsCnt == 0)
+ return false;
+
+ GlPrimitive* curPrimitive = nullptr;
+ for (size_t i = 0; i < cmdCnt; ++i)
+ {
+ switch (*(cmds + i))
+ {
+ case PathCommand::Close:
+ {
+ if (curPrimitive && curPrimitive->mAAPoints.size() > 0 &&
+ (curPrimitive->mAAPoints[0].orgPt != curPrimitive->mAAPoints.back().orgPt) )
+ {
+ curPrimitive->mAAPoints.push_back(curPrimitive->mAAPoints[0].orgPt);
+ }
+ break;
+ }
+ case PathCommand::MoveTo:
+ mPrimitives.push_back(GlPrimitive());
+ curPrimitive = &mPrimitives.back();
+ case PathCommand::LineTo:
+ {
+ if (curPrimitive)
+ {
+ addPoint(*curPrimitive, pts[0]);
+ }
+ pts++;
+ break;
+ }
+ case PathCommand::CubicTo:
+ {
+ if (curPrimitive)
+ {
+ decomposeCubicCurve(*curPrimitive, curPrimitive->mAAPoints.back().orgPt, pts[0], pts[1], pts[2]);
+ }
+ pts += 3;
+ break;
+ }
+ }
+ }
+ return true;
+}
+
+bool GlGeometry::generateAAPoints(const Shape &shape, float strokeWd, RenderUpdateFlag flag)
+{
+ for (auto& shapeGeometry : mPrimitives)
+ {
+ std::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;
+
+ size_t nPoints = aaPts.size();
+ if (nPoints < 2)
+ {
+ return false;
+ }
+
+ 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 (sPoint == nPoints - 1)
+ sPoint = 0;
+
+ GlPoint normal = getNormal(aaPts[fPoint].orgPt, aaPts[sPoint].orgPt);
+
+ normalInfo[fPoint].normal1 = normal;
+ normalInfo[sPoint].normal2 = normal;
+ }
+ normalInfo[nPoints - 1].normal1 = normalInfo[0].normal1;
+ normalInfo[nPoints - 1].normal2 = normalInfo[0].normal2;
+
+ for (uint32_t i = 0; i < nPoints; ++i)
+ {
+ normalInfo[i].normalF = normalInfo[i].normal1 + normalInfo[i].normal2;
+ normalInfo[i].normalF.normalize();
+
+ float 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)
+ {
+ 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)
+ {
+ 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;
+}
+
+bool GlGeometry::tesselate(const Shape &shape, 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)
+ {
+ 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)
+ {
+ 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)
+{
+ GL_CHECK(glDisableVertexAttribArray(location));
+ mGpuBuffer->unbind(GlGpuBuffer::Target::ARRAY_BUFFER);
+}
+
+
+void GlGeometry::draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag)
+{
+ if (primitiveIndex >= mPrimitives.size())
+ {
+ return;
+ }
+ VertexDataArray& geometry = (flag == RenderUpdateFlag::Color) ? mPrimitives[primitiveIndex].mFill : mPrimitives[primitiveIndex].mStroke;
+
+ updateBuffer(location, geometry);
+ GL_CHECK(glDrawElements(GL_TRIANGLES, geometry.indices.size(), GL_UNSIGNED_INT, geometry.indices.data()));
+}
+
+
+void GlGeometry::updateBuffer(uint32_t location, const VertexDataArray& vertexArray)
+{
+ if (mGpuBuffer.get() == nullptr)
+ {
+ mGpuBuffer = make_unique<GlGpuBuffer>();
+ }
+ mGpuBuffer->updateBufferData(GlGpuBuffer::Target::ARRAY_BUFFER, vertexArray.vertices.size() * sizeof(VertexData), vertexArray.vertices.data());
+ GL_CHECK(glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), 0));
+ GL_CHECK(glEnableVertexAttribArray(location));
+}
+
+
+GlPoint GlGeometry::normalizePoint(const GlPoint &pt, float viewWd, float viewHt)
+{
+ GlPoint p;
+ p.x = (pt.x * 2.0f / viewWd) - 1.0f;
+ p.y = -1.0f * ((pt.y * 2.0f / viewHt) - 1.0f);
+ return p;
+}
+
+void GlGeometry::addGeometryPoint(VertexDataArray &geometry, const GlPoint &pt, float viewWd, float viewHt, float opacity)
+{
+ VertexData tv = { normalizePoint(pt, viewWd, viewHt), 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)
+{
+ primitve.mAAPoints.push_back(GlPoint(pt.x, pt.y));
+}
+
+void GlGeometry::addTriangleFanIndices(uint32_t &curPt, std::vector<uint32_t> &indices)
+{
+ indices.push_back(0);
+ indices.push_back(curPt - 1);
+ indices.push_back(curPt);
+}
+
+void GlGeometry::addQuadIndices(uint32_t &curPt, std::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)
+{
+ if (isBezierFlat(pt1, cpt1, cpt2, pt2))
+ {
+ addPoint(primitve, pt2);
+ 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);
+ decomposeCubicCurve(primitve, p1234, p234, p34, pt2);
+}
+
#ifndef _TVG_GL_GEOMETRY_H_
#define _TVG_GL_GEOMETRY_H_
-#include "tvgGlGpuBuffer.h"
+#include "tvgGlCommon.h"
class GlPoint
{
float x = 0.0f;
float y = 0.0f;
+ GlPoint() = default;
+
GlPoint(float pX, float pY):x(pX), y(pY)
{}
vector<uint32_t> indices;
};
+struct GlPrimitive
+{
+ vector<SmoothPoint> mAAPoints;
+ VertexDataArray mFill;
+ VertexDataArray mStroke;
+};
+
+class GlGpuBuffer;
+
class GlGeometry
{
public:
- GlGeometry();
- void reset();
- void updateBuffer(const uint32_t location, const VertexDataArray& geometry);
- void draw(const VertexDataArray& geometry);
+
+ uint32_t getPrimitiveCount();
bool decomposeOutline(const Shape& shape);
bool generateAAPoints(const Shape& shape, float strokeWd, RenderUpdateFlag flag);
bool tesselate(const Shape &shape, float viewWd, float viewHt, RenderUpdateFlag flag);
-
- const VertexDataArray& getFill();
- const VertexDataArray& getStroke();
+ void disableVertex(uint32_t location);
+ void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag);
private:
- GlPoint normalizePoint(GlPoint &pt, float viewWd, float viewHt);
- void addGeometryPoint(VertexDataArray &geometry, GlPoint &pt, float viewWd, float viewHt, float opacity);
- GlPoint getNormal(GlPoint &p1, GlPoint &p2);
- float dotProduct(GlPoint &p1, GlPoint &p2);
- GlPoint extendEdge(GlPoint &pt, GlPoint &normal, float scalar);
- void addPoint(const GlPoint &pt);
+ GlPoint normalizePoint(const GlPoint &pt, float viewWd, float viewHt);
+ 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);
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(const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2);
+ void decomposeCubicCurve(GlPrimitive& primitve, const GlPoint &pt1, const GlPoint &cpt1, const GlPoint &cpt2, const GlPoint &pt2);
+ void updateBuffer(const uint32_t location, const VertexDataArray& vertexArray);
unique_ptr<GlGpuBuffer> mGpuBuffer;
- vector<SmoothPoint> mAAPoints;
- VertexDataArray mFill;
- VertexDataArray mStroke;
+ vector<GlPrimitive> mPrimitives;
};
#endif /* _TVG_GL_GEOMETRY_H_ */
--- /dev/null
+#include "tvgGlCommon.h"
+#include "tvgGlGpuBuffer.h"
+
+#include <assert.h>
+
+GlGpuBuffer::GlGpuBuffer()
+{
+ GL_CHECK(glGenBuffers(1, &mGlBufferId));
+ assert(mGlBufferId != GL_INVALID_VALUE);
+}
+
+
+GlGpuBuffer::~GlGpuBuffer()
+{
+ if (mGlBufferId)
+ {
+ GL_CHECK(glDeleteBuffers(1, &mGlBufferId));
+ }
+}
+
+
+void GlGpuBuffer::updateBufferData(Target target, uint32_t size, const void* data)
+{
+ GL_CHECK(glBindBuffer(static_cast<uint32_t>(target), mGlBufferId));
+ GL_CHECK(glBufferData(static_cast<uint32_t>(target), size, data, GL_STATIC_DRAW));
+}
+
+
+void GlGpuBuffer::unbind(Target target)
+{
+ GL_CHECK(glBindBuffer(static_cast<uint32_t>(target), 0));
+}
\ No newline at end of file
GlGpuBuffer();
~GlGpuBuffer();
- void updateBufferData(Target target, uint32_t size, void* data);
-
+ void updateBufferData(Target target, uint32_t size, const void* data);
+ void unbind(Target target);
private:
uint32_t mGlBufferId = 0;
--- /dev/null
+#include "tvgGlCommon.h"
+#include "tvgGlProgram.h"
+
+#include <GLES2/gl2.h>
+
+
+static std::vector<string> gStdAttributes = {
+ "aLocation"
+};
+
+static std::vector<string> gStdUniforms = {
+ "uColor"
+};
+
+uint32_t GlProgram::mCurrentProgram = 0;
+map<string, int32_t> GlProgram::mAttributeBuffer;
+map<string, int32_t> GlProgram::mUniformBuffer;
+
+
+unique_ptr<GlProgram> GlProgram::gen(std::shared_ptr<GlShader> shader)
+{
+ return make_unique<GlProgram>(shader);
+}
+
+
+GlProgram::GlProgram(std::shared_ptr<GlShader> shader)
+{
+ linkProgram(shader);
+ load();
+
+ for (auto name : gStdAttributes)
+ {
+ getAttributeLocation(name.c_str());
+ }
+ for (auto name : gStdUniforms)
+ {
+ getUniformLocation(name.c_str());
+ }
+
+}
+
+
+GlProgram::~GlProgram()
+{
+ if (mCurrentProgram == mProgramObj)
+ {
+ unload();
+ }
+ glDeleteProgram(mProgramObj);
+}
+
+
+void GlProgram::load()
+{
+ if (mCurrentProgram == mProgramObj)
+ {
+ return;
+ }
+
+ mCurrentProgram = mProgramObj;
+ GL_CHECK(glUseProgram(mProgramObj));
+
+}
+
+
+void GlProgram::unload()
+{
+ mCurrentProgram = 0;
+}
+
+
+int32_t GlProgram::getAttributeLocation(const char* name)
+{
+ if (mAttributeBuffer.find(name) != mAttributeBuffer.end())
+ {
+ return mAttributeBuffer[name];
+ }
+ GL_CHECK(int32_t location = glGetAttribLocation(mCurrentProgram, name));
+ if (location != -1)
+ {
+ mAttributeBuffer[name] = location;
+ }
+ return location;
+}
+
+
+int32_t GlProgram::getUniformLocation(const char* name)
+{
+ if (mUniformBuffer.find(name) != mUniformBuffer.end())
+ {
+ return mUniformBuffer[name];
+ }
+ GL_CHECK(int32_t location = glGetUniformLocation(mCurrentProgram, name));
+ if (location != -1)
+ {
+ mUniformBuffer[name] = location;
+ }
+ return location;
+
+}
+
+
+void GlProgram::setUniformValue(int32_t location, float r, float g, float b, float a)
+{
+ glUniform4f(location, r, g, b, a);
+}
+
+
+void GlProgram::linkProgram(std::shared_ptr<GlShader> shader)
+{
+ GLint linked;
+
+ // Create the program object
+ uint32_t progObj = glCreateProgram();
+ assert(progObj);
+
+ glAttachShader(progObj, shader->getVertexShader());
+ glAttachShader(progObj, shader->getFragmentShader());
+
+ // Link the program
+ glLinkProgram(progObj);
+
+ // Check the link status
+ glGetProgramiv(progObj, GL_LINK_STATUS, &linked);
+
+ if (!linked)
+ {
+ GLint infoLen = 0;
+ glGetProgramiv(progObj, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 0)
+ {
+ char* infoLog = new char[infoLen];
+ glGetProgramInfoLog(progObj, infoLen, NULL, infoLog);
+ std::cout << "Error linking shader: " << infoLog << std::endl;
+ delete[] infoLog;
+
+ }
+ glDeleteProgram(progObj);
+ progObj = 0;
+ assert(0);
+ }
+ mProgramObj = progObj;
+}
+
#include "tvgGlShader.h"
+#include <memory>
#include <map>
-
class GlProgram
{
public:
- GlProgram(shared_ptr<GlShader> shader);
- void create();
+ static std::unique_ptr<GlProgram> gen(std::shared_ptr<GlShader> shader);
+ GlProgram(std::shared_ptr<GlShader> shader);
+ ~GlProgram();
+
void load();
+ void unload();
int32_t getAttributeLocation(const char* name);
int32_t getUniformLocation(const char* name);
void setUniformValue(int32_t location, float r, float g, float b, float a);
private:
- void linkProgram();
- std::shared_ptr<GlShader> mShader;
+
+ void linkProgram(std::shared_ptr<GlShader> shader);
uint32_t mProgramObj;
static uint32_t mCurrentProgram;
#ifndef _TVG_GL_RENDERER_CPP_
#define _TVG_GL_RENDERER_CPP_
-#include "tvgCommon.h"
+#include "tvgGlShaderSrc.h"
+#include "tvgGlGpuBuffer.h"
+#include "tvgGlGeometry.h"
+#include "tvgGlCommon.h"
#include "tvgGlRenderer.h"
/************************************************************************/
bool GlRenderer::clear()
{
//TODO: (Request) to clear target
+ // Will be adding glClearColor for input buffer
+ return true;
+}
+
+
+bool GlRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h)
+{
+ assert(w > 0 && h > 0);
+
+ surface.stride = stride;
+ surface.w = w;
+ surface.h = h;
return true;
}
+
+void GlRenderer::flush()
+{
+ GL_CHECK(glFinish());
+ mColorProgram->unload();
+}
+
+
bool GlRenderer::render(const Shape& shape, void *data)
{
GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
- //TODO:
+ uint8_t r, g, b, a;
+ size_t flags = static_cast<size_t>(sdata->updateFlag);
+
+ GL_CHECK(glViewport(0, 0, sdata->viewWd, sdata->viewHt));
+
+ uint32_t geometryCnt = sdata->geometry->getPrimitiveCount();
+ for (uint32_t i = 0; i < geometryCnt; ++i)
+ {
+ mColorProgram->load();
+ if (flags & RenderUpdateFlag::Color)
+ {
+ shape.fill(&r, &g, &b, &a);
+ drawPrimitive(*(sdata->geometry), (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f, i, RenderUpdateFlag::Color);
+ }
+ if (flags & RenderUpdateFlag::Stroke)
+ {
+ shape.strokeColor(&r, &g, &b, &a);
+ drawPrimitive(*(sdata->geometry), (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, (float)a / 255.0f, i, RenderUpdateFlag::Stroke);
+ }
+ }
return true;
}
GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
- //TODO:
-
- free(sdata);
+ delete sdata;
return true;
}
{
//prepare shape data
GlShape* sdata = static_cast<GlShape*>(data);
- if (!sdata) {
- sdata = static_cast<GlShape*>(calloc(1, sizeof(GlShape)));
+ if (!sdata)
+ {
+ sdata = new GlShape;
assert(sdata);
}
+ sdata->viewWd = static_cast<float>(surface.w);
+ sdata->viewHt = static_cast<float>(surface.h);
+ sdata->updateFlag = flags;
- if (flags & RenderUpdateFlag::Path) {
- //TODO: Updated Vertices
- }
+ if (sdata->updateFlag == RenderUpdateFlag::None) return nullptr;
- if (flags & RenderUpdateFlag::Transform) {
- //TODO: Updated Transform
- }
+ initShaders();
+
+ sdata->geometry = make_unique<GlGeometry>();
- //TODO:
+ //invisible?
+ uint8_t alphaF, alphaS;
+ shape.fill(nullptr, nullptr, nullptr, &alphaF);
+ shape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
+ auto strokeWd = shape.strokeWidth();
+ if (alphaF == 0 && alphaS == 0) return sdata;
+
+ if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke) )
+ {
+ if (!sdata->geometry->decomposeOutline(shape)) return sdata;
+ if (!sdata->geometry->generateAAPoints(shape, static_cast<float>(strokeWd), sdata->updateFlag)) return sdata;
+ if (!sdata->geometry->tesselate(shape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata;
+ }
return sdata;
}
int GlRenderer::term()
{
+ if (inst()->mColorProgram.get())
+ {
+ inst()->mColorProgram.reset(nullptr);
+ }
return RenderInitializer::term(renderInit);
}
}
+void GlRenderer::initShaders()
+{
+ if (!mColorProgram.get())
+ {
+ shared_ptr<GlShader> shader = GlShader::gen(COLOR_VERT_SHADER, COLOR_FRAG_SHADER);
+ mColorProgram = GlProgram::gen(shader);
+ }
+ mColorProgram->load();
+ mColorUniformLoc = mColorProgram->getUniformLocation("uColor");
+ mVertexAttrLoc = mColorProgram->getAttributeLocation("aLocation");
+}
+
+
+void GlRenderer::drawPrimitive(GlGeometry& geometry, float r, float g, float b, float a, uint32_t primitiveIndex, RenderUpdateFlag flag)
+{
+ mColorProgram->setUniformValue(mColorUniformLoc, r, g, b, a);
+ geometry.draw(mVertexAttrLoc, primitiveIndex, flag);
+ geometry.disableVertex(mVertexAttrLoc);
+
+}
+
#endif /* _TVG_GL_RENDERER_CPP_ */
#define _TVG_GL_RENDERER_H_
#include "tvgGlCommon.h"
+#include "tvgGlProgram.h"
-namespace tvg
-{
class GlRenderer : public RenderMethod
{
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
bool dispose(const Shape& shape, void *data) override;
bool render(const Shape& shape, void *data) override;
- bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h)
- {
- return 0;
- };
+ bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
+ void flush();
bool clear() override;
uint32_t ref() override;
uint32_t unref() override;
GlRenderer(){};
~GlRenderer(){};
- std::unique_ptr<GlProgram> mColorProgram;
- int32_t mColorUniform;
- uint32_t mVertexAttrID;
-};
+ void initShaders();
+ void drawPrimitive(GlGeometry& geometry, float r, float g, float b, float a, uint32_t primitiveIndex, RenderUpdateFlag flag);
-}
+ unique_ptr<GlProgram> mColorProgram;
+ int32_t mColorUniformLoc;
+ uint32_t mVertexAttrLoc;
+};
#endif /* _TVG_GL_RENDERER_H_ */
--- /dev/null
+#include "tvgGlCommon.h"
+#include "tvgGlShader.h"
+
+#include <GLES2/gl2.h>
+
+
+shared_ptr<GlShader> GlShader::gen(const char * vertSrc, const char * fragSrc)
+{
+ shared_ptr<GlShader> shader = make_shared<GlShader>();
+ shader->createShader(vertSrc, fragSrc);
+ return shader;
+}
+
+
+GlShader::~GlShader()
+{
+ glDeleteShader(mVtShader);
+ glDeleteShader(mFrShader);
+}
+
+uint32_t GlShader::getVertexShader()
+{
+ return mVtShader;
+}
+
+
+uint32_t GlShader::getFragmentShader()
+{
+ return mFrShader;
+}
+
+
+void GlShader::createShader(const char* vertSrc, const char* fragSrc)
+{
+ mVtShader = complileShader(GL_VERTEX_SHADER, const_cast<char*>(vertSrc));
+ mFrShader = complileShader(GL_FRAGMENT_SHADER, const_cast<char*>(fragSrc));
+}
+
+
+uint32_t GlShader::complileShader(uint32_t type, char* shaderSrc)
+{
+ GLuint shader;
+ GLint compiled;
+
+ // Create the shader object
+ shader = glCreateShader(type);
+ assert(shader);
+
+ // Load the shader source
+ glShaderSource(shader, 1, &shaderSrc, NULL);
+
+ // Compile the shader
+ glCompileShader(shader);
+
+ // Check the compile status
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+
+ if (!compiled)
+ {
+ GLint infoLen = 0;
+
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+
+ if (infoLen > 0)
+ {
+ char* infoLog = new char[infoLen];
+ glGetShaderInfoLog(shader, infoLen, NULL, infoLog);
+ std::cout << "Error compiling shader: " << infoLog << std::endl;
+ delete[] infoLog;
+ }
+ glDeleteShader(shader);
+ assert(0);
+ }
+
+ return shader;
+}
+
#ifndef _TVG_GL_SHADER_H_
#define _TVG_GL_SHADER_H_
+#include <memory>
+
class GlShader
{
public:
- static shared_ptr<GlShader> gen(const char * vertSrc, const char * fragSrc);
+ static std::shared_ptr<GlShader> gen(const char * vertSrc, const char * fragSrc);
+ ~GlShader();
uint32_t getVertexShader();
uint32_t getFragmentShader();
--- /dev/null
+#include "tvgGlShaderSrc.h"
+
+const char* COLOR_VERT_SHADER =
+"attribute highp vec4 aLocation; \n"
+"uniform highp vec4 uColor; \n"
+"varying highp vec4 vcolor; \n"
+"varying highp float vOpacity; \n"
+"void main() \n"
+"{ \n"
+" gl_Position = vec4(aLocation.xy, 0.0, 1.0); \n"
+" vcolor = uColor; \n"
+" vOpacity = aLocation.z; \n"
+"} \n";
+
+const char* COLOR_FRAG_SHADER =
+"varying highp vec4 vcolor; \n"
+"varying highp float vOpacity; \n"
+"void main() \n"
+"{ \n"
+" gl_FragColor = vec4(vcolor.xyz, vcolor.w*vOpacity); \n"
+"} \n";
+
--- /dev/null
+#ifndef _TVG_GL_SHADERSRC_H_
+#define _TVG_GL_SHADERSRC_H_
+
+extern const char* COLOR_VERT_SHADER;
+extern const char* COLOR_FRAG_SHADER;
+
+#endif /* _TVG_GL_SHADERSRC_H_ */
Result GlCanvas::sync() noexcept
{
+ auto renderer = dynamic_cast<GlRenderer*>(Canvas::pImpl.get()->renderer);
+ assert(renderer);
+
+ renderer->flush();
return Result::Success;
}
gcc -o testLinearGradient testLinearGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
gcc -o testRadialGradient testRadialGradient.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
gcc -o testGradientTransform testGradientTransform.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
- gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
- gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
+# gcc -o testSvg testSvg.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
+# gcc -o testSvg2 testSvg2.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
+ gcc -o testGlShape testGlShape.cpp -g -lstdc++ `pkg-config --cflags --libs elementary tizenvg`
--- /dev/null
+#include <tizenvg.h>
+#include <Elementary.h>
+
+using namespace std;
+
+#define WIDTH 800
+#define HEIGHT 800
+#define BPP 4
+static Evas_GL_API *glapi;
+static unique_ptr<tvg::GlCanvas> canvas;
+
+static void
+tvgtest()
+{
+ //Initialize TizenVG Engine
+ tvg::Initializer::init(tvg::CanvasEngine::Gl);
+
+
+ //Create a Canvas
+ canvas = tvg::GlCanvas::gen();
+ canvas->target(nullptr, WIDTH * BPP, WIDTH, HEIGHT);
+
+ //Prepare a Shape (Rectangle + Rectangle + Circle + Circle)
+ auto shape1 = tvg::Shape::gen();
+ shape1->appendRect(0, 0, 200, 200, 0); //x, y, w, h, cornerRadius
+ shape1->appendRect(100, 100, 300, 300, 100); //x, y, w, h, cornerRadius
+ shape1->appendCircle(400, 400, 100, 100); //cx, cy, radiusW, radiusH
+ shape1->appendCircle(400, 500, 170, 100); //cx, cy, radiusW, radiusH
+ shape1->fill(255, 255, 0, 255); //r, g, b, a
+ shape1->stroke(255, 0, 0, 255); //r, g, b, a
+ shape1->stroke(10.0f);
+
+ /* Push the shape into the Canvas drawing list
+ When this shape is into the canvas list, the shape could update & prepare
+ internal data asynchronously for coming rendering.
+ Canvas keeps this shape node unless user call canvas->clear() */
+ canvas->push(move(shape1));
+}
+
+static void
+init_gl(Evas_Object *obj)
+{
+ tvgtest();
+}
+
+static void
+del_gl(Evas_Object *obj)
+{
+ //Terminate TizenVG Engine
+ tvg::Initializer::term(tvg::CanvasEngine::Gl);
+}
+
+static void
+draw_gl(Evas_Object *obj)
+{
+ Evas_GL_API *gl = elm_glview_gl_api_get(obj);
+ int w, h;
+ elm_glview_size_get(obj, &w, &h);
+ gl->glViewport(0, 0, w, h);
+ gl->glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ gl->glClear(GL_COLOR_BUFFER_BIT);
+ gl->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ gl->glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE);
+ gl->glEnable(GL_BLEND);
+
+ canvas->draw();
+ canvas->sync();
+}
+
+void
+win_del(void *data, Evas_Object *o, void *ev)
+{
+ elm_exit();
+}
+
+int main(int argc, char **argv)
+{
+ //Show the result using EFL...
+ elm_init(argc, argv);
+
+ Eo* win = elm_win_util_standard_add(nullptr, "TizenVG Test");
+ evas_object_smart_callback_add(win, "delete,request", win_del, 0);
+
+ // create a new glview object
+ Eo* gl = elm_glview_add(win);
+ glapi = elm_glview_gl_api_get(gl);
+ evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+
+ elm_glview_mode_set(gl, ELM_GLVIEW_ALPHA);
+ elm_glview_resize_policy_set(gl, ELM_GLVIEW_RESIZE_POLICY_RECREATE);
+ elm_glview_render_policy_set(gl, ELM_GLVIEW_RENDER_POLICY_ON_DEMAND);
+
+ evas_object_resize(gl, WIDTH, HEIGHT);
+
+ // initialize callback function gets registered here
+ elm_glview_init_func_set(gl, init_gl);
+ // delete callback function gets registered here
+ elm_glview_del_func_set(gl, del_gl);
+ elm_glview_render_func_set(gl, draw_gl);
+
+ evas_object_show(gl);
+
+ elm_object_focus_set(gl, EINA_TRUE);
+
+ evas_object_geometry_set(win, 0, 0, WIDTH, HEIGHT);
+ evas_object_show(win);
+
+ elm_run();
+ elm_shutdown();
+
+ return 0;
+}