thorvg/src/lib/gl_engine/tvgGlRenderer.cpp
Vincenzo Pupillo 2fd9bb76b6 gl_engine: fixed the signature of the prepare() method in GlRenderer
The implementation of the virtual prepare() method is different from that of RenderMethod.
from that of RenderMethod, so the compilation fails. This modification solves the problem.
2022-10-02 18:46:47 +09:00

384 lines
11 KiB
C++

/*
* Copyright (c) 2020 - 2022 Samsung Electronics Co., Ltd. All rights reserved.
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "tvgGlRenderer.h"
#include "tvgGlGpuBuffer.h"
#include "tvgGlGeometry.h"
#include "tvgGlPropertyInterface.h"
/************************************************************************/
/* Internal Class Implementation */
/************************************************************************/
static int32_t initEngineCnt = false;
static int32_t rendererCnt = 0;
static void _termEngine()
{
if (rendererCnt > 0) return;
//TODO: Clean up global resources
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
#define NOISE_LEVEL 0.5f
bool GlRenderer::clear()
{
//TODO: (Request) to clear target
// Will be adding glClearColor for input buffer
return true;
}
bool GlRenderer::target(TVG_UNUSED 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;
}
bool GlRenderer::sync()
{
GL_CHECK(glFinish());
GlRenderTask::unload();
return true;
}
RenderRegion GlRenderer::region(TVG_UNUSED RenderData data)
{
return {0, 0, 0, 0};
}
bool GlRenderer::preRender()
{
if (mRenderTasks.size() == 0)
{
initShaders();
}
GlRenderTask::unload();
// Blend function for straight alpha
GL_CHECK(glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
GL_CHECK(glEnable(GL_BLEND));
return true;
}
bool GlRenderer::postRender()
{
//TODO: called just after render()
return true;
}
Compositor* GlRenderer::target(TVG_UNUSED const RenderRegion& region)
{
//TODO: Prepare frameBuffer & Setup render target for composition
return nullptr;
}
bool GlRenderer::beginComposite(TVG_UNUSED Compositor* cmp, CompositeMethod method, uint32_t opacity)
{
//TODO: delete the given compositor and restore the context
return false;
}
bool GlRenderer::endComposite(TVG_UNUSED Compositor* cmp)
{
//TODO: delete the given compositor and restore the context
return false;
}
bool GlRenderer::renderImage(TVG_UNUSED void* data)
{
return false;
}
bool GlRenderer::renderImageMesh(TVG_UNUSED void* data)
{
return false;
}
bool GlRenderer::renderShape(RenderData data)
{
auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
uint8_t r, g, b, a;
size_t flags = static_cast<size_t>(sdata->updateFlag);
GL_CHECK(glViewport(0, 0, (GLsizei)sdata->viewWd, (GLsizei)sdata->viewHt));
uint32_t primitiveCount = sdata->geometry->getPrimitiveCount();
for (uint32_t i = 0; i < primitiveCount; ++i)
{
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
{
const Fill* gradient = sdata->shape->fill();
if (gradient != nullptr)
{
drawPrimitive(*sdata, gradient, i, RenderUpdateFlag::Gradient);
}
}
if(flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Transform))
{
sdata->shape->fillColor(&r, &g, &b, &a);
if (a > 0)
{
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Color);
}
}
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
{
sdata->shape->strokeColor(&r, &g, &b, &a);
if (a > 0)
{
drawPrimitive(*sdata, r, g, b, a, i, RenderUpdateFlag::Stroke);
}
}
}
return true;
}
bool GlRenderer::dispose(RenderData data)
{
auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
delete sdata;
return true;
}
RenderData GlRenderer::prepare(TVG_UNUSED Surface* image, TVG_UNUSED Polygon* triangles, TVG_UNUSED uint32_t triangleCnt, TVG_UNUSED RenderData data, TVG_UNUSED const RenderTransform* transform, TVG_UNUSED uint32_t opacity, TVG_UNUSED Array<RenderData>& clips, TVG_UNUSED RenderUpdateFlag flags)
{
//TODO:
return nullptr;
}
RenderData GlRenderer::prepare(const Shape& shape, RenderData data, const RenderTransform* transform, TVG_UNUSED uint32_t opacity, Array<RenderData>& clips, RenderUpdateFlag flags)
{
//prepare shape data
GlShape* sdata = static_cast<GlShape*>(data);
if (!sdata) {
sdata = new GlShape;
sdata->shape = &shape;
}
sdata->viewWd = static_cast<float>(surface.w);
sdata->viewHt = static_cast<float>(surface.h);
sdata->updateFlag = flags;
if (sdata->updateFlag == RenderUpdateFlag::None) return sdata;
sdata->geometry = make_unique<GlGeometry>();
//invisible?
uint8_t alphaF, alphaS;
shape.fillColor(nullptr, nullptr, nullptr, &alphaF);
shape.strokeColor(nullptr, nullptr, nullptr, &alphaS);
auto strokeWd = shape.strokeWidth();
if ( ((sdata->updateFlag & RenderUpdateFlag::Gradient) == 0) &&
((sdata->updateFlag & RenderUpdateFlag::Color) && alphaF == 0) &&
((sdata->updateFlag & RenderUpdateFlag::Stroke) && alphaS == 0) )
{
return sdata;
}
sdata->geometry->updateTransform(transform, sdata->viewWd, sdata->viewHt);
if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Stroke | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
{
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;
}
RenderRegion GlRenderer::viewport()
{
return {0, 0, INT32_MAX, INT32_MAX};
}
bool GlRenderer::viewport(TVG_UNUSED const RenderRegion& vp)
{
//TODO:
return true;
}
int GlRenderer::init(uint32_t threads)
{
if ((initEngineCnt++) > 0) return true;
//TODO:
return true;
}
int32_t GlRenderer::init()
{
return initEngineCnt;
}
int GlRenderer::term()
{
if ((--initEngineCnt) > 0) return true;
initEngineCnt = 0;
_termEngine();
return true;
}
GlRenderer* GlRenderer::gen()
{
return new GlRenderer();
}
GlRenderer::~GlRenderer()
{
mRenderTasks.clear();
--rendererCnt;
if (rendererCnt == 0 && initEngineCnt == 0) _termEngine();
}
void GlRenderer::initShaders()
{
// Solid Color Renderer
mRenderTasks.push_back(GlColorRenderTask::gen());
// Linear Gradient Renderer
mRenderTasks.push_back(GlLinearGradientRenderTask::gen());
// Radial Gradient Renderer
mRenderTasks.push_back(GlRadialGradientRenderTask::gen());
}
void GlRenderer::drawPrimitive(GlShape& sdata, uint8_t r, uint8_t g, uint8_t b, uint8_t a, uint32_t primitiveIndex, RenderUpdateFlag flag)
{
GlColorRenderTask* renderTask = static_cast<GlColorRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_Color].get());
assert(renderTask);
renderTask->load();
float* matrix = sdata.geometry->getTransforMatrix();
PropertyInterface::clearData(renderTask);
renderTask->setColor(r, g, b, a);
renderTask->setTransform(FORMAT_SIZE_MAT_4x4, matrix);
int32_t vertexLoc = renderTask->getLocationPropertyId();
renderTask->uploadValues();
sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
sdata.geometry->disableVertex(vertexLoc);
}
void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, uint32_t primitiveIndex, RenderUpdateFlag flag)
{
const Fill::ColorStop* stops = nullptr;
auto stopCnt = fill->colorStops(&stops);
if (stopCnt < 2) return;
GlGradientRenderTask* rTask = nullptr;
auto size = sdata.geometry->getPrimitiveSize(primitiveIndex);
auto matrix = sdata.geometry->getTransforMatrix();
switch (fill->identifier()) {
case TVG_CLASS_ID_LINEAR: {
float x1, y1, x2, y2;
GlLinearGradientRenderTask *renderTask = static_cast<GlLinearGradientRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_LinGradient].get());
assert(renderTask);
rTask = renderTask;
renderTask->load();
PropertyInterface::clearData(renderTask);
const LinearGradient* grad = static_cast<const LinearGradient*>(fill);
grad->linear(&x1, &y1, &x2, &y2);
renderTask->setStartPosition(x1, y1);
renderTask->setEndPosition(x2, y2);
break;
}
case TVG_CLASS_ID_RADIAL: {
float x1, y1, r1;
GlRadialGradientRenderTask *renderTask = static_cast<GlRadialGradientRenderTask*>(mRenderTasks[GlRenderTask::RenderTypes::RT_RadGradient].get());
assert(renderTask);
rTask = renderTask;
renderTask->load();
PropertyInterface::clearData(renderTask);
const RadialGradient* grad = static_cast<const RadialGradient*>(fill);
grad->radial(&x1, &y1, &r1);
renderTask->setStartPosition(x1, y1);
renderTask->setStartRadius(r1);
break;
}
}
if (rTask) {
auto vertexLoc = rTask->getLocationPropertyId();
rTask->setPrimitveSize(size.x, size.y);
rTask->setCanvasSize(sdata.viewWd, sdata.viewHt);
rTask->setNoise(NOISE_LEVEL);
rTask->setStopCount((int)stopCnt);
rTask->setTransform(FORMAT_SIZE_MAT_4x4, matrix);
for (uint32_t i = 0; i < stopCnt; ++i) {
rTask->setStopColor(i, stops[i].offset, stops[i].r, stops[i].g, stops[i].b, stops[i].a);
}
rTask->uploadValues();
sdata.geometry->draw(vertexLoc, primitiveIndex, flag);
sdata.geometry->disableVertex(vertexLoc);
}
}