diff --git a/.gitignore b/.gitignore index 3b90d3af..af30a22a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ testRadialGradient testGradientTransform testSvg testSvg2 +testGlShape diff --git a/src/lib/gl_engine/meson.build b/src/lib/gl_engine/meson.build old mode 100644 new mode 100755 index 5494f692..a5409a74 --- a/src/lib/gl_engine/meson.build +++ b/src/lib/gl_engine/meson.build @@ -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( diff --git a/src/lib/gl_engine/tvgGlCommon.h b/src/lib/gl_engine/tvgGlCommon.h old mode 100644 new mode 100755 index f68666a4..c5969545 --- a/src/lib/gl_engine/tvgGlCommon.h +++ b/src/lib/gl_engine/tvgGlCommon.h @@ -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; diff --git a/src/lib/gl_engine/tvgGlGeometry.cpp b/src/lib/gl_engine/tvgGlGeometry.cpp new file mode 100755 index 00000000..59b730bd --- /dev/null +++ b/src/lib/gl_engine/tvgGlGeometry.cpp @@ -0,0 +1,319 @@ +#include "tvgGlGpuBuffer.h" +#include "tvgGlGeometry.h" +#include "tvgGlCommon.h" + +#include + + +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(&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 normalInfo; + constexpr float blurDir = -1.0f; + float antiAliasWidth = 1.0f; + vector& 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& 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(); + } + 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 &indices) +{ + indices.push_back(0); + indices.push_back(curPt - 1); + indices.push_back(curPt); +} + +void GlGeometry::addQuadIndices(uint32_t &curPt, std::vector &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); +} + diff --git a/src/lib/gl_engine/tvgGlGeometry.h b/src/lib/gl_engine/tvgGlGeometry.h old mode 100644 new mode 100755 index 8f7cc610..9f87efa9 --- a/src/lib/gl_engine/tvgGlGeometry.h +++ b/src/lib/gl_engine/tvgGlGeometry.h @@ -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 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 &indices); - void addQuadIndices(uint32_t &curPt, vector &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 mGpuBuffer; vector 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 &indices); + void addQuadIndices(uint32_t &curPt, vector &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 mGpuBuffer; + vector mPrimitives; +}; + #endif /* _TVG_GL_GEOMETRY_H_ */ diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.cpp b/src/lib/gl_engine/tvgGlGpuBuffer.cpp new file mode 100755 index 00000000..2aaba198 --- /dev/null +++ b/src/lib/gl_engine/tvgGlGpuBuffer.cpp @@ -0,0 +1,32 @@ +#include "tvgGlCommon.h" +#include "tvgGlGpuBuffer.h" + +#include + +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(target), mGlBufferId)); + GL_CHECK(glBufferData(static_cast(target), size, data, GL_STATIC_DRAW)); +} + + +void GlGpuBuffer::unbind(Target target) +{ + GL_CHECK(glBindBuffer(static_cast(target), 0)); +} \ No newline at end of file diff --git a/src/lib/gl_engine/tvgGlGpuBuffer.h b/src/lib/gl_engine/tvgGlGpuBuffer.h old mode 100644 new mode 100755 index 79dd26d6..3116001c --- a/src/lib/gl_engine/tvgGlGpuBuffer.h +++ b/src/lib/gl_engine/tvgGlGpuBuffer.h @@ -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; diff --git a/src/lib/gl_engine/tvgGlProgram.cpp b/src/lib/gl_engine/tvgGlProgram.cpp new file mode 100755 index 00000000..dbf87622 --- /dev/null +++ b/src/lib/gl_engine/tvgGlProgram.cpp @@ -0,0 +1,144 @@ +#include "tvgGlCommon.h" +#include "tvgGlProgram.h" + +#include + + +static std::vector gStdAttributes = { + "aLocation" +}; + +static std::vector gStdUniforms = { + "uColor" +}; + +uint32_t GlProgram::mCurrentProgram = 0; +map GlProgram::mAttributeBuffer; +map GlProgram::mUniformBuffer; + + +unique_ptr GlProgram::gen(std::shared_ptr shader) +{ + return make_unique(shader); +} + + +GlProgram::GlProgram(std::shared_ptr 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 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; +} + diff --git a/src/lib/gl_engine/tvgGlProgram.h b/src/lib/gl_engine/tvgGlProgram.h old mode 100644 new mode 100755 index d485d3d2..5df0e4f1 --- a/src/lib/gl_engine/tvgGlProgram.h +++ b/src/lib/gl_engine/tvgGlProgram.h @@ -3,22 +3,25 @@ #include "tvgGlShader.h" +#include #include - class GlProgram { public: - GlProgram(shared_ptr shader); - void create(); + static std::unique_ptr gen(std::shared_ptr shader); + GlProgram(std::shared_ptr 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 mShader; + + void linkProgram(std::shared_ptr shader); uint32_t mProgramObj; static uint32_t mCurrentProgram; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp old mode 100644 new mode 100755 index 1ca9588b..ecabf6ad --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -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(data); if (!sdata) return false; - //TODO: + uint8_t r, g, b, a; + size_t flags = static_cast(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(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(data); - if (!sdata) { - sdata = static_cast(calloc(1, sizeof(GlShape))); + if (!sdata) + { + sdata = new GlShape; assert(sdata); } + sdata->viewWd = static_cast(surface.w); + sdata->viewHt = static_cast(surface.h); + sdata->updateFlag = flags; - if (flags & RenderUpdateFlag::Path) { - //TODO: Updated Vertices + if (sdata->updateFlag == RenderUpdateFlag::None) return nullptr; + + initShaders(); + + sdata->geometry = make_unique(); + + //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(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 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_ */ diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h old mode 100644 new mode 100755 index 3ef0ee97..5214a63d --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -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 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 mColorProgram; + int32_t mColorUniformLoc; + uint32_t mVertexAttrLoc; }; -} - #endif /* _TVG_GL_RENDERER_H_ */ diff --git a/src/lib/gl_engine/tvgGlShader.cpp b/src/lib/gl_engine/tvgGlShader.cpp new file mode 100755 index 00000000..a655159c --- /dev/null +++ b/src/lib/gl_engine/tvgGlShader.cpp @@ -0,0 +1,77 @@ +#include "tvgGlCommon.h" +#include "tvgGlShader.h" + +#include + + +shared_ptr GlShader::gen(const char * vertSrc, const char * fragSrc) +{ + shared_ptr shader = make_shared(); + 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(vertSrc)); + mFrShader = complileShader(GL_FRAGMENT_SHADER, const_cast(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; +} + diff --git a/src/lib/gl_engine/tvgGlShader.h b/src/lib/gl_engine/tvgGlShader.h old mode 100644 new mode 100755 index 36b125a9..85bf1160 --- a/src/lib/gl_engine/tvgGlShader.h +++ b/src/lib/gl_engine/tvgGlShader.h @@ -1,10 +1,13 @@ #ifndef _TVG_GL_SHADER_H_ #define _TVG_GL_SHADER_H_ +#include + class GlShader { public: - static shared_ptr gen(const char * vertSrc, const char * fragSrc); + static std::shared_ptr gen(const char * vertSrc, const char * fragSrc); + ~GlShader(); uint32_t getVertexShader(); uint32_t getFragmentShader(); diff --git a/src/lib/gl_engine/tvgGlShaderSrc.cpp b/src/lib/gl_engine/tvgGlShaderSrc.cpp new file mode 100755 index 00000000..cdd25f0f --- /dev/null +++ b/src/lib/gl_engine/tvgGlShaderSrc.cpp @@ -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"; + diff --git a/src/lib/gl_engine/tvgGlShaderSrc.h b/src/lib/gl_engine/tvgGlShaderSrc.h new file mode 100755 index 00000000..e6d3b911 --- /dev/null +++ b/src/lib/gl_engine/tvgGlShaderSrc.h @@ -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_ */ diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp old mode 100644 new mode 100755 index 7d3903c2..80a00177 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -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(Canvas::pImpl.get()->renderer); + assert(renderer); + + renderer->flush(); return Result::Success; } diff --git a/src/lib/tvgRenderCommon.h b/src/lib/tvgRenderCommon.h old mode 100644 new mode 100755 diff --git a/src/lib/tvgShape.cpp b/src/lib/tvgShape.cpp old mode 100644 new mode 100755 diff --git a/test/makefile b/test/makefile old mode 100644 new mode 100755 index 8dce9e9b..aca250bf --- a/test/makefile +++ b/test/makefile @@ -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` diff --git a/test/testGlShape.cpp b/test/testGlShape.cpp new file mode 100755 index 00000000..077057e2 --- /dev/null +++ b/test/testGlShape.cpp @@ -0,0 +1,113 @@ +#include +#include + +using namespace std; + +#define WIDTH 800 +#define HEIGHT 800 +#define BPP 4 +static Evas_GL_API *glapi; +static unique_ptr 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; +}