updated copyright.
[platform/core/graphics/tizenvg.git] / src / lib / gl_engine / tvgGlRenderer.cpp
1 /*
2  * Copyright (c) 2020 - 2023 the ThorVG project. All rights reserved.
3
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:
10
11  * The above copyright notice and this permission notice shall be included in all
12  * copies or substantial portions of the Software.
13
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
20  * SOFTWARE.
21  */
22
23 #include "tvgGlRenderer.h"
24 #include "tvgGlGpuBuffer.h"
25 #include "tvgGlGeometry.h"
26 #include "tvgGlPropertyInterface.h"
27
28 /************************************************************************/
29 /* Internal Class Implementation                                        */
30 /************************************************************************/
31 static int32_t initEngineCnt = false;
32 static int32_t rendererCnt = 0;
33
34
35 static void _termEngine()
36 {
37     if (rendererCnt > 0) return;
38
39     //TODO: Clean up global resources
40 }
41
42 /************************************************************************/
43 /* External Class Implementation                                        */
44 /************************************************************************/
45
46 #define NOISE_LEVEL 0.5f
47
48 bool GlRenderer::clear()
49 {
50     //TODO: (Request) to clear target
51     // Will be adding glClearColor for input buffer
52     return true;
53 }
54
55
56 bool GlRenderer::target(TVG_UNUSED uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h)
57 {
58     assert(w > 0 && h > 0);
59
60     surface.stride = stride;
61     surface.w = w;
62     surface.h = h;
63
64     return true;
65 }
66
67
68 bool GlRenderer::sync()
69 {
70     GL_CHECK(glFinish());
71     GlRenderTask::unload();
72     return true;
73 }
74
75
76 RenderRegion GlRenderer::region(TVG_UNUSED RenderData data)
77 {
78     return {0, 0, 0, 0};
79 }
80
81
82 bool GlRenderer::preRender()
83 {
84     if (mRenderTasks.size() == 0)
85     {
86         initShaders();
87     }
88     GlRenderTask::unload();
89
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));
93     return true;
94 }
95
96
97 bool GlRenderer::postRender()
98 {
99     //TODO: called just after render()
100
101     return true;
102 }
103
104
105 Compositor* GlRenderer::target(TVG_UNUSED const RenderRegion& region)
106 {
107     //TODO: Prepare frameBuffer & Setup render target for composition
108     return nullptr;
109 }
110
111
112 bool GlRenderer::beginComposite(TVG_UNUSED Compositor* cmp, CompositeMethod method, uint32_t opacity)
113 {
114     //TODO: delete the given compositor and restore the context
115     return false;
116 }
117
118
119 bool GlRenderer::endComposite(TVG_UNUSED Compositor* cmp)
120 {
121     //TODO: delete the given compositor and restore the context
122     return false;
123 }
124
125
126 bool GlRenderer::renderImage(TVG_UNUSED void* data)
127 {
128     return false;
129 }
130
131
132 bool GlRenderer::renderImageMesh(TVG_UNUSED void* data)
133 {
134     return false;
135 }
136
137
138 bool GlRenderer::renderShape(RenderData data)
139 {
140     auto sdata = static_cast<GlShape*>(data);
141     if (!sdata) return false;
142
143     uint8_t r, g, b, a;
144     size_t flags = static_cast<size_t>(sdata->updateFlag);
145
146     GL_CHECK(glViewport(0, 0, (GLsizei)sdata->viewWd, (GLsizei)sdata->viewHt));
147
148     uint32_t primitiveCount = sdata->geometry->getPrimitiveCount();
149     for (uint32_t i = 0; i < primitiveCount; ++i)
150     {
151         if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
152         {
153             const Fill* gradient = sdata->shape->fill();
154             if (gradient != nullptr)
155             {
156                 drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
157             }
158         }
159
160         if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform))
161         {
162             sdata->shape->fillColor(&r, &g, &b, &a);
163             if (a > 0)
164             {
165                 drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
166             }
167         }
168
169         if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
170         {
171             sdata->shape->strokeColor(&r, &g, &b, &a);
172             if (a > 0)
173             {
174                 drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
175             }
176         }
177     }
178
179     return true;
180 }
181
182
183 bool GlRenderer::dispose(RenderData data)
184 {
185     auto sdata = static_cast<GlShape*>(data);
186     if (!sdata) return false;
187
188     delete sdata;
189     return true;
190 }
191
192
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)
194 {
195     //TODO:
196     return nullptr;
197 }
198
199
200 RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
201 {
202     //prepare shape data
203     GlShape* sdata = static_cast<GlShape*>(data);
204     if (!sdata) {
205         sdata = new GlShape;
206         sdata->shape = &shape;
207     }
208
209     sdata->viewWd = static_cast<float>(surface.w);
210     sdata->viewHt = static_cast<float>(surface.h);
211     sdata->updateFlag = flags;
212
213     if (sdata->updateFlag == RenderUpdateFlag::None) return sdata;
214
215     sdata->geometry = make_unique<GlGeometry>();
216
217     //invisible?
218     uint8_t alphaF, alphaS;
219     shape.fillColor(nullptr, nullptr, nullptr, &alphaF);
220     shape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
221     auto strokeWd = shape.strokeWidth();
222
223     if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
224          ((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 0) &&
225          ((sdata->updateFlag & RenderUpdateFlag::Stroke) && alphaS == 0) )
226     {
227         return sdata;
228     }
229
230     sdata->geometry->updateTransform(transform, sdata->viewWd, sdata->viewHt);
231
232     if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
233     {
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;
237     }
238     return sdata;
239 }
240
241
242 RenderRegion GlRenderer::viewport()
243 {
244     return {0, 0, INT32_MAX, INT32_MAX};
245 }
246
247
248 bool GlRenderer::viewport(TVG_UNUSED const RenderRegion& vp)
249 {
250     //TODO:
251     return true;
252 }
253
254
255 int GlRenderer::init(uint32_t threads)
256 {
257     if ((initEngineCnt++) > 0) return true;
258
259     //TODO:
260
261     return true;
262 }
263
264
265 int32_t GlRenderer::init()
266 {
267     return initEngineCnt;
268 }
269
270
271 int GlRenderer::term()
272 {
273     if ((--initEngineCnt) > 0) return true;
274
275     initEngineCnt = 0;
276
277    _termEngine();
278
279     return true;
280 }
281
282
283 GlRenderer* GlRenderer::gen()
284 {
285     return new GlRenderer();
286 }
287
288
289 GlRenderer::~GlRenderer()
290 {
291     mRenderTasks.clear();
292
293     --rendererCnt;
294
295     if (rendererCnt == 0 && initEngineCnt == 0) _termEngine();
296 }
297
298
299 void GlRenderer::initShaders()
300 {
301     // Solid Color Renderer
302     mRenderTasks.push_back(GlColorRenderTask::gen());
303
304     // Linear Gradient Renderer
305     mRenderTasks.push_back(GlLinearGradientRenderTask::gen());
306
307     // Radial Gradient Renderer
308     mRenderTasks.push_back(GlRadialGradientRenderTask::gen());
309 }
310
311
312 void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint32_t primitiveIndex, RenderUpdateFlag flag)
313 {
314     GlColorRenderTask* renderTask = static_cast<GlColorRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_Color].get());
315     assert(renderTask);
316     renderTask->load();
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);
325
326 }
327
328
329 void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, uint32_t primitiveIndex, RenderUpdateFlag flag)
330 {
331     const Fill::ColorStop* stops = nullptr;
332     auto stopCnt = fill->colorStops(&stops);
333     if (stopCnt < 2) return;
334
335     GlGradientRenderTask* rTask = nullptr;
336     auto size = sdata.geometry->getPrimitiveSize(primitiveIndex);
337     auto matrix = sdata.geometry->getTransforMatrix();
338
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());
343             assert(renderTask);
344             rTask = renderTask;
345             renderTask->load();
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);
351             break;
352         }
353         case TVG_CLASS_ID_RADIAL: {
354             float x1, y1, r1;
355             GlRadialGradientRenderTask *renderTask = static_cast<GlRadialGradientRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_RadGradient].get());
356             assert(renderTask);
357             rTask = renderTask;
358             renderTask->load();
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);
364             break;
365         }
366     }
367     if (rTask) {
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);
374
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);
377         }
378
379         rTask->uploadValues();
380         sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
381         sdata.geometry->disableVertex(vertexLoc);
382     }
383 }
384