mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
gl_engine: fix coding convention.
no logical changes.
This commit is contained in:
parent
d0799d8fa1
commit
d08d87dc0b
6 changed files with 68 additions and 142 deletions
1
AUTHORS
1
AUTHORS
|
@ -9,3 +9,4 @@ Michal Szczecinski <m.szczecinsk@partner.samsung.com>
|
|||
Shinwoo Kim <cinoo.kim@samsung.com>
|
||||
Piotr Kalota <p.kalota@samsung.com>
|
||||
Vincent Torri <vincent.torri@gmail.com>
|
||||
Pankaj Kumar <pankaj.m1@samsung.com>
|
||||
|
|
|
@ -37,10 +37,7 @@ uint32_t GlGeometry::getPrimitiveCount()
|
|||
|
||||
const GlSize GlGeometry::getPrimitiveSize(const uint32_t primitiveIndex) const
|
||||
{
|
||||
if (primitiveIndex >= mPrimitives.size())
|
||||
{
|
||||
return GlSize();
|
||||
}
|
||||
if (primitiveIndex >= mPrimitives.size()) return GlSize();
|
||||
GlSize size = mPrimitives[primitiveIndex].mBottomRight - mPrimitives[primitiveIndex].mTopLeft;
|
||||
return size;
|
||||
}
|
||||
|
@ -55,22 +52,17 @@ bool GlGeometry::decomposeOutline(const Shape& shape)
|
|||
auto ptsCnt = shape.pathCoords(const_cast<const Point**>(&pts));
|
||||
|
||||
//No actual shape data
|
||||
if (cmdCnt == 0 || ptsCnt == 0)
|
||||
return false;
|
||||
if (cmdCnt == 0 || ptsCnt == 0) return false;
|
||||
|
||||
GlPrimitive* curPrimitive = nullptr;
|
||||
GlPoint min = { FLT_MAX, FLT_MAX };
|
||||
GlPoint max = { 0.0f, 0.0f };
|
||||
|
||||
for (size_t i = 0; i < cmdCnt; ++i)
|
||||
{
|
||||
for (unsigned i = 0; i < cmdCnt; ++i) {
|
||||
switch (*(cmds + i)) {
|
||||
case PathCommand::Close: {
|
||||
if (curPrimitive)
|
||||
{
|
||||
if (curPrimitive->mAAPoints.size() > 0 &&
|
||||
(curPrimitive->mAAPoints[0].orgPt != curPrimitive->mAAPoints.back().orgPt))
|
||||
{
|
||||
if (curPrimitive) {
|
||||
if (curPrimitive->mAAPoints.size() > 0 && (curPrimitive->mAAPoints[0].orgPt != curPrimitive->mAAPoints.back().orgPt)) {
|
||||
curPrimitive->mAAPoints.push_back(curPrimitive->mAAPoints[0].orgPt);
|
||||
}
|
||||
curPrimitive->mIsClosed = true;
|
||||
|
@ -78,13 +70,10 @@ bool GlGeometry::decomposeOutline(const Shape& shape)
|
|||
break;
|
||||
}
|
||||
case PathCommand::MoveTo: {
|
||||
if (curPrimitive)
|
||||
{
|
||||
if (curPrimitive) {
|
||||
curPrimitive->mTopLeft = min;
|
||||
curPrimitive->mBottomRight = max;
|
||||
if (curPrimitive->mAAPoints.size() > 2 &&
|
||||
(curPrimitive->mAAPoints[0].orgPt == curPrimitive->mAAPoints.back().orgPt))
|
||||
{
|
||||
if (curPrimitive->mAAPoints.size() > 2 && (curPrimitive->mAAPoints[0].orgPt == curPrimitive->mAAPoints.back().orgPt)) {
|
||||
curPrimitive->mIsClosed = true;
|
||||
}
|
||||
}
|
||||
|
@ -93,25 +82,18 @@ bool GlGeometry::decomposeOutline(const Shape& shape)
|
|||
}
|
||||
__attribute__ ((fallthrough));
|
||||
case PathCommand::LineTo: {
|
||||
if (curPrimitive)
|
||||
{
|
||||
addPoint(*curPrimitive, pts[0], min, max);
|
||||
}
|
||||
if (curPrimitive) addPoint(*curPrimitive, pts[0], min, max);
|
||||
pts++;
|
||||
break;
|
||||
}
|
||||
case PathCommand::CubicTo: {
|
||||
if (curPrimitive)
|
||||
{
|
||||
decomposeCubicCurve(*curPrimitive, curPrimitive->mAAPoints.back().orgPt, pts[0], pts[1], pts[2], min, max);
|
||||
}
|
||||
if (curPrimitive) decomposeCubicCurve(*curPrimitive, curPrimitive->mAAPoints.back().orgPt, pts[0], pts[1], pts[2], min, max);
|
||||
pts += 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (curPrimitive)
|
||||
{
|
||||
if (curPrimitive) {
|
||||
curPrimitive->mTopLeft = min;
|
||||
curPrimitive->mBottomRight = max;
|
||||
}
|
||||
|
@ -121,8 +103,7 @@ bool GlGeometry::decomposeOutline(const Shape& shape)
|
|||
|
||||
bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd, RenderUpdateFlag flag)
|
||||
{
|
||||
for (auto& shapeGeometry : mPrimitives)
|
||||
{
|
||||
for (auto& shapeGeometry : mPrimitives) {
|
||||
vector<PointNormals> normalInfo;
|
||||
constexpr float blurDir = -1.0f;
|
||||
float antiAliasWidth = 1.0f;
|
||||
|
@ -131,58 +112,41 @@ bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd,
|
|||
const float stroke = (strokeWd > 1) ? strokeWd - antiAliasWidth : strokeWd;
|
||||
|
||||
size_t nPoints = aaPts.size();
|
||||
if (nPoints < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
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)
|
||||
{
|
||||
for (size_t i = 0; i < nPoints - 1; ++i) {
|
||||
fPoint = i;
|
||||
sPoint = i + 1;
|
||||
if (shapeGeometry.mIsClosed && sPoint == nPoints - 1)
|
||||
{
|
||||
sPoint = 0;
|
||||
}
|
||||
|
||||
if (shapeGeometry.mIsClosed && sPoint == nPoints - 1) sPoint = 0;
|
||||
GlPoint normal = getNormal(aaPts[fPoint].orgPt, aaPts[sPoint].orgPt);
|
||||
|
||||
normalInfo[fPoint].normal1 = normal;
|
||||
normalInfo[sPoint].normal2 = normal;
|
||||
}
|
||||
if (shapeGeometry.mIsClosed)
|
||||
{
|
||||
if (shapeGeometry.mIsClosed) {
|
||||
normalInfo[nPoints - 1].normal1 = normalInfo[0].normal1;
|
||||
normalInfo[nPoints - 1].normal2 = normalInfo[0].normal2;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
normalInfo[nPoints - 1].normal1 = normalInfo[nPoints - 1].normal2;
|
||||
normalInfo[0].normal2 = normalInfo[0].normal1;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < nPoints; ++i)
|
||||
{
|
||||
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);
|
||||
auto 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 | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform))
|
||||
{
|
||||
if (flag & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) {
|
||||
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 | RenderUpdateFlag::Transform))
|
||||
{
|
||||
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||
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);
|
||||
|
@ -196,28 +160,21 @@ bool GlGeometry::generateAAPoints(TVG_UNUSED const Shape& shape, float strokeWd,
|
|||
|
||||
bool GlGeometry::tesselate(TVG_UNUSED const Shape& shape, float viewWd, float viewHt, RenderUpdateFlag flag)
|
||||
{
|
||||
for (auto& shapeGeometry : mPrimitives)
|
||||
{
|
||||
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 | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform) )
|
||||
{
|
||||
if (flag & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient | RenderUpdateFlag::Transform)) {
|
||||
uint32_t i = 0;
|
||||
for (size_t pt = 0; pt < aaPts.size(); ++pt)
|
||||
{
|
||||
for (size_t pt = 0; pt < aaPts.size(); ++pt) {
|
||||
addGeometryPoint(fill, aaPts[pt].fillOuter, viewWd, viewHt, opaque);
|
||||
if (i > 1)
|
||||
{
|
||||
addTriangleFanIndices(i, fill.indices);
|
||||
}
|
||||
if (i > 1) addTriangleFanIndices(i, fill.indices);
|
||||
++i;
|
||||
}
|
||||
for (size_t pt = 1; pt < aaPts.size(); ++pt)
|
||||
{
|
||||
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);
|
||||
|
@ -225,27 +182,23 @@ bool GlGeometry::tesselate(TVG_UNUSED const Shape& shape, float viewWd, float vi
|
|||
addQuadIndices(i, fill.indices);
|
||||
}
|
||||
}
|
||||
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform))
|
||||
{
|
||||
if (flag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||
uint32_t i = 0;
|
||||
for (size_t pt = 1; pt < aaPts.size(); ++pt)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
@ -268,10 +221,8 @@ void GlGeometry::disableVertex(uint32_t location)
|
|||
|
||||
void GlGeometry::draw(const uint32_t location, const uint32_t primitiveIndex, RenderUpdateFlag flag)
|
||||
{
|
||||
if (primitiveIndex >= mPrimitives.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (primitiveIndex >= mPrimitives.size()) return;
|
||||
|
||||
VertexDataArray& geometry = (flag == RenderUpdateFlag::Stroke) ? mPrimitives[primitiveIndex].mStroke : mPrimitives[primitiveIndex].mFill;
|
||||
|
||||
updateBuffer(location, geometry);
|
||||
|
@ -281,10 +232,8 @@ void GlGeometry::draw(const uint32_t location, const uint32_t primitiveIndex, Re
|
|||
|
||||
void GlGeometry::updateBuffer(uint32_t location, const VertexDataArray& vertexArray)
|
||||
{
|
||||
if (mGpuBuffer.get() == nullptr)
|
||||
{
|
||||
mGpuBuffer = make_unique<GlGpuBuffer>();
|
||||
}
|
||||
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));
|
||||
|
@ -329,6 +278,7 @@ void GlGeometry::addPoint(GlPrimitive& primitve, const GlPoint& pt, GlPoint& min
|
|||
if (pt.y < min.y) min.y = pt.y;
|
||||
if (pt.x > max.x) max.x = pt.x;
|
||||
if (pt.y > max.y) max.y = pt.y;
|
||||
|
||||
primitve.mAAPoints.push_back(GlPoint(pt.x, pt.y));
|
||||
}
|
||||
|
||||
|
@ -357,30 +307,25 @@ bool GlGeometry::isBezierFlat(const GlPoint& p1, const GlPoint& c1, const GlPoin
|
|||
|
||||
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;
|
||||
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, GlPoint& min, GlPoint& max)
|
||||
{
|
||||
if (isBezierFlat(pt1, cpt1, cpt2, pt2))
|
||||
{
|
||||
if (isBezierFlat(pt1, cpt1, cpt2, pt2)) {
|
||||
addPoint(primitve, pt2, min, max);
|
||||
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, min, max);
|
||||
|
@ -390,8 +335,7 @@ void GlGeometry::decomposeCubicCurve(GlPrimitive& primitve, const GlPoint& pt1,
|
|||
|
||||
void GlGeometry::updateTransform(const RenderTransform* transform, float w, float h)
|
||||
{
|
||||
if (transform)
|
||||
{
|
||||
if (transform) {
|
||||
mTransform.x = transform->x;
|
||||
mTransform.y = transform->y;
|
||||
mTransform.angle = transform->degree;
|
||||
|
|
|
@ -74,10 +74,12 @@ public:
|
|||
GlPoint() = default;
|
||||
|
||||
GlPoint(float pX, float pY):x(pX), y(pY)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
GlPoint(const Point& rhs):GlPoint(rhs.x, rhs.y)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
GlPoint(const GlPoint& rhs) = default;
|
||||
GlPoint(GlPoint&& rhs) = default;
|
||||
|
@ -94,19 +96,15 @@ public:
|
|||
|
||||
bool operator== (const GlPoint& rhs)
|
||||
{
|
||||
if (&rhs == this)
|
||||
return true;
|
||||
if (rhs.x == this->x && rhs.y == this->y)
|
||||
return true;
|
||||
if (&rhs == this) return true;
|
||||
if (rhs.x == this->x && rhs.y == this->y) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!= (const GlPoint& rhs)
|
||||
{
|
||||
if (&rhs == this)
|
||||
return true;
|
||||
if (rhs.x != this->x || rhs.y != this->y)
|
||||
return true;
|
||||
if (&rhs == this) return true;
|
||||
if (rhs.x != this->x || rhs.y != this->y) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -158,9 +156,8 @@ public:
|
|||
|
||||
void normalize()
|
||||
{
|
||||
auto length = sqrtf( (x * x) + (y * y) );
|
||||
if (length != 0.0f)
|
||||
{
|
||||
auto length = sqrtf((x * x) + (y * y));
|
||||
if (length != 0.0f) {
|
||||
const auto inverseLen = 1.0f / length;
|
||||
x *= inverseLen;
|
||||
y *= inverseLen;
|
||||
|
@ -229,7 +226,6 @@ struct GlTransform
|
|||
float scale = 1.0f;
|
||||
float w;
|
||||
float h;
|
||||
|
||||
float matrix[16];
|
||||
};
|
||||
|
||||
|
|
|
@ -67,14 +67,11 @@ VertexProperty& PropertyInterface::addProperty(GlRenderTask* rTask, std::shared_
|
|||
void PropertyInterface::setProperty(GlRenderTask* rTask, int32_t propId, int32_t count, float* data)
|
||||
{
|
||||
std::map<int32_t, VertexProperty>::iterator itr = rTask->getUniformVertexProperty().find(propId);
|
||||
if (itr->second.propertyId == -1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (itr->second.propertyId == -1) return;
|
||||
|
||||
VertexProperty& prop = itr->second;
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
for (int i = 0; i < count; ++i) {
|
||||
prop.propertyValues.set(data[i]);
|
||||
}
|
||||
}
|
||||
|
@ -82,12 +79,8 @@ void PropertyInterface::setProperty(GlRenderTask* rTask, int32_t propId, int32_t
|
|||
int32_t PropertyInterface::getPropertyId(GlRenderTask* rTask, std::string name)
|
||||
{
|
||||
std::map<int32_t, VertexProperty>& vertexProperty = rTask->getUniformVertexProperty();
|
||||
for (auto& property : vertexProperty)
|
||||
{
|
||||
if (property.second.propertyName == name)
|
||||
{
|
||||
return property.second.propertyId;
|
||||
}
|
||||
for (auto& property : vertexProperty) {
|
||||
if (property.second.propertyName == name) return property.second.propertyId;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -96,12 +89,8 @@ int32_t PropertyInterface::getPropertyId(GlRenderTask* rTask, std::string name)
|
|||
VertexProperty& PropertyInterface::getProperty(GlRenderTask* rTask, std::string name)
|
||||
{
|
||||
std::map<int32_t, VertexProperty>& vertexProperty = rTask->getUniformVertexProperty();
|
||||
for (auto& property : vertexProperty)
|
||||
{
|
||||
if (property.second.propertyName == name)
|
||||
{
|
||||
return property.second;
|
||||
}
|
||||
for (auto& property : vertexProperty) {
|
||||
if (property.second.propertyName == name) return property.second;
|
||||
}
|
||||
return mEmptyProperty;
|
||||
}
|
||||
|
@ -110,10 +99,7 @@ VertexProperty& PropertyInterface::getProperty(GlRenderTask* rTask, std::string
|
|||
VertexProperty& PropertyInterface::getProperty(GlRenderTask* rTask, int32_t propId)
|
||||
{
|
||||
std::map<int32_t, VertexProperty>& vertexProperty = rTask->getUniformVertexProperty();
|
||||
if (vertexProperty.find(propId) != vertexProperty.end())
|
||||
{
|
||||
return vertexProperty[propId];
|
||||
}
|
||||
if (vertexProperty.find(propId) != vertexProperty.end()) return vertexProperty[propId];
|
||||
return mEmptyProperty;
|
||||
}
|
||||
|
||||
|
@ -121,8 +107,7 @@ VertexProperty& PropertyInterface::getProperty(GlRenderTask* rTask, int32_t prop
|
|||
void PropertyInterface::clearData(GlRenderTask* rTask)
|
||||
{
|
||||
std::map<int32_t, VertexProperty>& vertexProperty = rTask->getUniformVertexProperty();
|
||||
for (auto& prop : vertexProperty)
|
||||
{
|
||||
for (auto& prop : vertexProperty) {
|
||||
prop.second.propertyValues.clear();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue