2 * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 #include "tvgGlRenderer.h"
24 #include "tvgGlGpuBuffer.h"
25 #include "tvgGlGeometry.h"
26 #include "tvgGlPropertyInterface.h"
28 /************************************************************************/
29 /* Internal Class Implementation */
30 /************************************************************************/
31 static int32_t initEngineCnt = false;
32 static int32_t rendererCnt = 0;
35 static void _termEngine()
37 if (rendererCnt > 0) return;
39 //TODO: Clean up global resources
42 /************************************************************************/
43 /* External Class Implementation */
44 /************************************************************************/
46 #define NOISE_LEVEL 0.5f
48 bool GlRenderer::clear()
50 //TODO: (Request) to clear target
51 // Will be adding glClearColor for input buffer
56 bool GlRenderer::target(TVG_UNUSED uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h)
58 assert(w > 0 && h > 0);
60 surface.stride = stride;
68 bool GlRenderer::sync()
71 GlRenderTask::unload();
76 RenderRegion GlRenderer::region(TVG_UNUSED RenderData data)
82 bool GlRenderer::preRender()
84 if (mRenderTasks.size() == 0)
88 GlRenderTask::unload();
90 // Blend function for straight alpha
91 GL_CHECK(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
92 GL_CHECK(glEnable(GL_BLEND));
97 bool GlRenderer::postRender()
99 //TODO: called just after render()
105 Compositor* GlRenderer::target(TVG_UNUSED const RenderRegion& region)
107 //TODO: Prepare frameBuffer & Setup render target for composition
112 bool GlRenderer::beginComposite(TVG_UNUSED Compositor* cmp, CompositeMethod method, uint32_t opacity)
114 //TODO: delete the given compositor and restore the context
119 bool GlRenderer::endComposite(TVG_UNUSED Compositor* cmp)
121 //TODO: delete the given compositor and restore the context
126 bool GlRenderer::renderImage(TVG_UNUSED void* data)
132 bool GlRenderer::renderImageMesh(TVG_UNUSED void* data)
138 bool GlRenderer::renderShape(RenderData data)
140 auto sdata = static_cast<GlShape*>(data);
141 if (!sdata) return false;
144 size_t flags = static_cast<size_t>(sdata->updateFlag);
146 GL_CHECK(glViewport(0, 0, (GLsizei)sdata->viewWd, (GLsizei)sdata->viewHt));
148 uint32_t primitiveCount = sdata->geometry->getPrimitiveCount();
149 for (uint32_t i = 0; i < primitiveCount; ++i)
151 if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
153 const Fill* gradient = sdata->shape->fill();
154 if (gradient != nullptr)
156 drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
160 if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform))
162 sdata->shape->fillColor(&r, &g, &b, &a);
165 drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
169 if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
171 sdata->shape->strokeColor(&r, &g, &b, &a);
174 drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
183 bool GlRenderer::dispose(RenderData data)
185 auto sdata = static_cast<GlShape*>(data);
186 if (!sdata) return false;
193 RenderData GlRenderer::prepare(TVG_UNUSED Surface* image, TVG_UNUSED RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array<RenderData>& clips, TVG_UNUSED RenderUpdateFlag flags)
200 RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
203 GlShape* sdata = static_cast<GlShape*>(data);
206 sdata->shape = &shape;
209 sdata->viewWd = static_cast<float>(surface.w);
210 sdata->viewHt = static_cast<float>(surface.h);
211 sdata->updateFlag = flags;
213 if (sdata->updateFlag == RenderUpdateFlag::None) return sdata;
215 sdata->geometry = make_unique<GlGeometry>();
218 uint8_t alphaF, alphaS;
219 shape.fillColor(nullptr, nullptr, nullptr, &alphaF);
220 shape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
221 auto strokeWd = shape.strokeWidth();
223 if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
224 ((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 0) &&
225 ((sdata->updateFlag & RenderUpdateFlag::Stroke) && alphaS == 0) )
230 sdata->geometry->updateTransform(transform, sdata->viewWd, sdata->viewHt);
232 if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
234 if (!sdata->geometry->decomposeOutline(shape)) return sdata;
235 if (!sdata->geometry->generateAAPoints(shape, static_cast<float>(strokeWd), sdata->updateFlag)) return sdata;
236 if (!sdata->geometry->tesselate(shape, sdata->viewWd, sdata->viewHt, sdata->updateFlag)) return sdata;
242 RenderRegion GlRenderer::viewport()
244 return {0, 0, INT32_MAX, INT32_MAX};
248 bool GlRenderer::viewport(TVG_UNUSED const RenderRegion& vp)
255 int GlRenderer::init(uint32_t threads)
257 if ((initEngineCnt++) > 0) return true;
265 int32_t GlRenderer::init()
267 return initEngineCnt;
271 int GlRenderer::term()
273 if ((--initEngineCnt) > 0) return true;
283 GlRenderer* GlRenderer::gen()
285 return new GlRenderer();
289 GlRenderer::~GlRenderer()
291 mRenderTasks.clear();
295 if (rendererCnt == 0 && initEngineCnt == 0) _termEngine();
299 void GlRenderer::initShaders()
301 // Solid Color Renderer
302 mRenderTasks.push_back(GlColorRenderTask::gen());
304 // Linear Gradient Renderer
305 mRenderTasks.push_back(GlLinearGradientRenderTask::gen());
307 // Radial Gradient Renderer
308 mRenderTasks.push_back(GlRadialGradientRenderTask::gen());
312 void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint32_t primitiveIndex, RenderUpdateFlag flag)
314 GlColorRenderTask* renderTask = static_cast<GlColorRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_Color].get());
317 float* matrix = sdata.geometry->getTransforMatrix();
318 PropertyInterface::clearData(renderTask);
319 renderTask->setColor(r, g, b, a);
320 renderTask->setTransform(FORMAT_SIZE_MAT_4x4, matrix);
321 int32_t vertexLoc = renderTask->getLocationPropertyId();
322 renderTask->uploadValues();
323 sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
324 sdata.geometry->disableVertex(vertexLoc);
329 void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, uint32_t primitiveIndex, RenderUpdateFlag flag)
331 const Fill::ColorStop* stops = nullptr;
332 auto stopCnt = fill->colorStops(&stops);
333 if (stopCnt < 2) return;
335 GlGradientRenderTask* rTask = nullptr;
336 auto size = sdata.geometry->getPrimitiveSize(primitiveIndex);
337 auto matrix = sdata.geometry->getTransforMatrix();
339 switch (fill->id()) {
340 case TVG_CLASS_ID_LINEAR: {
341 float x1, y1, x2, y2;
342 GlLinearGradientRenderTask *renderTask = static_cast<GlLinearGradientRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_LinGradient].get());
346 PropertyInterface::clearData(renderTask);
347 const LinearGradient* grad = static_cast<const LinearGradient*>(fill);
348 grad->linear(&x1, &y1, &x2, &y2);
349 renderTask->setStartPosition(x1, y1);
350 renderTask->setEndPosition(x2, y2);
353 case TVG_CLASS_ID_RADIAL: {
355 GlRadialGradientRenderTask *renderTask = static_cast<GlRadialGradientRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_RadGradient].get());
359 PropertyInterface::clearData(renderTask);
360 const RadialGradient* grad = static_cast<const RadialGradient*>(fill);
361 grad->radial(&x1, &y1, &r1);
362 renderTask->setStartPosition(x1, y1);
363 renderTask->setStartRadius(r1);
368 auto vertexLoc = rTask->getLocationPropertyId();
369 rTask->setPrimitveSize(size.x, size.y);
370 rTask->setCanvasSize(sdata.viewWd, sdata.viewHt);
371 rTask->setNoise(NOISE_LEVEL);
372 rTask->setStopCount((int)stopCnt);
373 rTask->setTransform(FORMAT_SIZE_MAT_4x4, matrix);
375 for (uint32_t i = 0; i < stopCnt; ++i) {
376 rTask->setStopColor(i, stops[i].offset, stops[i].r, stops[i].g, stops[i].b, stops[i].a);
379 rTask->uploadValues();
380 sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
381 sdata.geometry->disableVertex(vertexLoc);