gl_engine: implement gl infrastructure interfaces & test Gl shape sample

Change-Id: Ie142616bf02f9bd50ac8e88e31ed9f782dd6324b
Signed-off-by: Pranay Kumar Samanta <pranay.ks@samsung.com>
This commit is contained in:
Pranay Kumar Samanta 2020-06-10 18:14:42 +05:30 committed by Hermet Park
parent ec03afa83a
commit 968286df57
20 changed files with 904 additions and 67 deletions

1
.gitignore vendored
View file

@ -19,3 +19,4 @@ testRadialGradient
testGradientTransform
testSvg
testSvg2
testGlShape

6
src/lib/gl_engine/meson.build Normal file → Executable file
View file

@ -5,7 +5,13 @@ source_file = [
'tvgGlProgram.h',
'tvgGlRenderer.h',
'tvgGlShader.h',
'tvgGlShaderSrc.h',
'tvgGlGeometry.cpp',
'tvgGlGpuBuffer.cpp',
'tvgGlProgram.cpp',
'tvgGlRenderer.cpp',
'tvgGlShader.cpp',
'tvgGlShaderSrc.cpp',
]
glraster_dep = declare_dependency(

26
src/lib/gl_engine/tvgGlCommon.h Normal file → Executable file
View file

@ -2,11 +2,31 @@
#define _TVG_GL_COMMON_H_
#include "tvgCommon.h"
#include "tvgGlProgram.h"
#include "tvgGlShader.h"
#include "tvgGlGeometry.h"
#define GL_CHECK(x) \
x; \
do { \
GLenum glError = glGetError(); \
if(glError != GL_NO_ERROR) { \
printf("glGetError() = %i (0x%.8x) at line %s : %i\n", glError, glError, __FILE__, __LINE__); \
assert(0); \
} \
} while(0)
#define EGL_CHECK(x) \
x; \
do { \
EGLint eglError = eglGetError(); \
if(eglError != EGL_SUCCESS) { \
printf("eglGetError() = %i (0x%.8x) at line %s : %i\n", eglError, eglError, __FILE__, __LINE__); \
assert(0); \
} \
} while(0)
class GlGeometry;
struct GlShape
{
float viewWd;

View file

@ -0,0 +1,319 @@
#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);
}

62
src/lib/gl_engine/tvgGlGeometry.h Normal file → Executable file
View file

@ -1,7 +1,7 @@
#ifndef _TVG_GL_GEOMETRY_H_
#define _TVG_GL_GEOMETRY_H_
#include "tvgGlGpuBuffer.h"
#include "tvgGlCommon.h"
class GlPoint
{
@ -9,6 +9,8 @@ public:
float x = 0.0f;
float y = 0.0f;
GlPoint() = default;
GlPoint(float pX, float pY):x(pX), y(pY)
{}
@ -145,36 +147,42 @@ struct VertexDataArray
vector<uint32_t> indices;
};
class GlGeometry
struct GlPrimitive
{
public:
GlGeometry();
void reset();
void updateBuffer(const uint32_t location, const VertexDataArray& geometry);
void draw(const VertexDataArray& geometry);
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();
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);
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);
unique_ptr<GlGpuBuffer> mGpuBuffer;
vector<SmoothPoint> mAAPoints;
VertexDataArray mFill;
VertexDataArray mStroke;
};
class GlGpuBuffer;
class GlGeometry
{
public:
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);
void disableVertex(uint32_t location);
void draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag);
private:
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(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<GlPrimitive> mPrimitives;
};
#endif /* _TVG_GL_GEOMETRY_H_ */

View file

@ -0,0 +1,32 @@
#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));
}

4
src/lib/gl_engine/tvgGlGpuBuffer.h Normal file → Executable file
View file

@ -15,8 +15,8 @@ public:
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;

View file

@ -0,0 +1,144 @@
#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;
}

13
src/lib/gl_engine/tvgGlProgram.h Normal file → Executable file
View file

@ -3,22 +3,25 @@
#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;

111
src/lib/gl_engine/tvgGlRenderer.cpp Normal file → Executable file
View file

@ -17,7 +17,10 @@
#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"
/************************************************************************/
@ -33,16 +36,55 @@ static RenderInitializer renderInit;
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;
}
@ -53,9 +95,7 @@ bool GlRenderer::dispose(const Shape& shape, void *data)
GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
//TODO:
free(sdata);
delete sdata;
return true;
}
@ -64,21 +104,35 @@ void* GlRenderer::prepare(const Shape& shape, void* data, const RenderTransform*
{
//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;
initShaders();
sdata->geometry = make_unique<GlGeometry>();
//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;
}
if (flags & RenderUpdateFlag::Transform) {
//TODO: Updated Transform
}
//TODO:
return sdata;
}
@ -91,6 +145,10 @@ int GlRenderer::init()
int GlRenderer::term()
{
if (inst()->mColorProgram.get())
{
inst()->mColorProgram.reset(nullptr);
}
return RenderInitializer::term(renderInit);
}
@ -114,4 +172,25 @@ GlRenderer* GlRenderer::inst()
}
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_ */

20
src/lib/gl_engine/tvgGlRenderer.h Normal file → Executable file
View file

@ -18,9 +18,8 @@
#define _TVG_GL_RENDERER_H_
#include "tvgGlCommon.h"
#include "tvgGlProgram.h"
namespace tvg
{
class GlRenderer : public RenderMethod
{
@ -30,10 +29,8 @@ public:
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;
@ -46,11 +43,12 @@ private:
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_ */

View file

@ -0,0 +1,77 @@
#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;
}

5
src/lib/gl_engine/tvgGlShader.h Normal file → Executable file
View file

@ -1,10 +1,13 @@
#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();

View file

@ -0,0 +1,22 @@
#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";

View file

@ -0,0 +1,7 @@
#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_ */

4
src/lib/tvgGlCanvas.cpp Normal file → Executable file
View file

@ -59,6 +59,10 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
Result GlCanvas::sync() noexcept
{
auto renderer = dynamic_cast<GlRenderer*>(Canvas::pImpl.get()->renderer);
assert(renderer);
renderer->flush();
return Result::Success;
}

0
src/lib/tvgRenderCommon.h Normal file → Executable file
View file

0
src/lib/tvgShape.cpp Normal file → Executable file
View file

5
test/makefile Normal file → Executable file
View file

@ -15,5 +15,6 @@ all:
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`

113
test/testGlShape.cpp Executable file
View file

@ -0,0 +1,113 @@
#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;
}