Skip to content

Commit

Permalink
[SUTK] Added SUTK::RenderRectArray to draw an array of filled rectangles
Browse files Browse the repository at this point in the history
  • Loading branch information
ravi688 committed Aug 17, 2024
1 parent 81cffdd commit 01e8edc
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 5 deletions.
6 changes: 6 additions & 0 deletions sutk/include/sutk/Container.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ namespace SUTK
Vec2Df getScreenCoordsToLocalCoords(Vec2Df screenCoords) const;
// converts local coordinates in its rect (in centimeters) to global coordinates (in centimeters)
Vec2Df getLocalCoordsToScreenCoords(Vec2Df localCoords) const;
// overload for Rect2Df, does the exact same function as the above function, however, it doesn't modify the localRect.size
Rect2Df getLocalCoordsToScreenCoords(Rect2Df localRect) const
{
Vec2Df pos = getLocalCoordsToScreenCoords(localRect.getPosition());
return { pos, localRect.getSize() };
}

// addition and removal of child containers

Expand Down
26 changes: 26 additions & 0 deletions sutk/include/sutk/Geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ namespace SUTK
VertexIndexArray array;
bool isModified;
};
// Rect2D<f32>::size : this value is multiple by position vertex attribute
// Rect2D<f32>::position : this value is added to the above result
typedef Rect2D<f32> InstanceTransform;
typedef std::vector<InstanceTransform> InstanceTransformArray;
struct InstanceTransformArrayInfo
{
InstanceTransformArray array;
bool isModified;
};
struct LineStroke
{
f32 width;
Expand Down Expand Up @@ -54,6 +63,7 @@ namespace SUTK
private:
VertexPositionArrayInfo m_positionArrayInfo;
VertexIndexArrayInfo m_indexArrayInfo;
InstanceTransformArrayInfo m_transformArrayInfo;
std::optional<LineStrokeInfo> m_strokeInfo;
FillColorInfo m_fillColorInfo;
Topology m_topology;
Expand All @@ -74,6 +84,8 @@ namespace SUTK
Geometry& vertexPositionArray(const std::vector<VertexPosition>& positions) noexcept;
Geometry& vertexPosition(VertexPosition position) noexcept;

Geometry& instanceTransformArray(u32 transformCount) noexcept;
Geometry& instanceTransform(InstanceTransform transform) noexcept;

Geometry& lineStroke(LineStroke stroke, bool isDynamic = false) noexcept;
Geometry& lineStroke(float width, Color4 color = Color4::white(), bool isDynamic = false) noexcept
Expand All @@ -82,6 +94,8 @@ namespace SUTK
}
Geometry& fillColor(Color4 color) noexcept;

Geometry& array(u32 count) noexcept;

// getters

Topology getTopology() const noexcept { return m_topology; }
Expand All @@ -90,12 +104,24 @@ namespace SUTK
const VertexPositionArray& getVertexPositionArray() const { return m_positionArrayInfo.array; }
VertexIndexArray& getVertexIndexArrayForWrite() { m_indexArrayInfo.isModified = true; return m_indexArrayInfo.array; }
const VertexIndexArray& getVertexIndexArray() const { return m_indexArrayInfo.array; }
InstanceTransformArray& getInstanceTransformArrayForWrite() { m_transformArrayInfo.isModified = true; return m_transformArrayInfo.array; }
const InstanceTransformArray& getInstanceTransformArray() const { return m_transformArrayInfo.array; }

Color4 getFillColor() const { return m_fillColorInfo.color; }

bool isVertexIndexArrayModified() const noexcept { return m_indexArrayInfo.isModified; }
bool isVertexPositionArrayModified() const noexcept { return m_positionArrayInfo.isModified; }
bool isInstanceTransformArrayModified() const noexcept { return m_transformArrayInfo.isModified; }
bool isLineStrokeModified() const noexcept { return m_strokeInfo.has_value() && m_strokeInfo->isModified; }
bool isFillColorModified() const noexcept { return m_fillColorInfo.isModified; }

bool isModified() const noexcept
{
return isVertexIndexArrayModified() ||
isVertexPositionArrayModified() ||
isInstanceTransformArrayModified() ||
isLineStrokeModified() ||
isFillColorModified();
}
};
}
41 changes: 41 additions & 0 deletions sutk/include/sutk/RenderRectArray.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#pragma once

#include <sutk/defines.hpp> // for SUTK_API
#include <sutk/Renderable.hpp> // for SUTK::Renderable abstract class
#include <sutk/IColorable.hpp> // for SUTK::IColorable

namespace SUTK
{
class SUTK_API RenderRectFillArray : public GeometryRenderable, public IColorable
{
private:
Color4 m_color;
bool m_isColorDirty;
bool m_isActiveDirty;
std::vector<Rect2Df> m_rects;
bool m_isRectsDirty;

// overrides of Renderable::onGlobalCoordDirty(), and onContainerResize
void onGlobalCoordDirty() noexcept override;
void onContainerResize(Rect2Df rect, bool isPositionChanged, bool isSizeChanged) noexcept;


public:
// Constructors
RenderRectFillArray(UIDriver& driver, RenderableContainer* container) noexcept;

// Implementation of Renderable
virtual bool isDirty();
virtual void update();

// Overrides of Renderable::setActive
virtual void setActive(bool isActive) noexcept override;

const std::vector<Rect2Df>& getRects() const noexcept { return m_rects; }
std::vector<Rect2Df>& getRectsForWrite() noexcept;

virtual Color4 getColor() const noexcept { return m_color; }
// it must be called in the overriding method
virtual void setColor(const Color4 color) noexcept;
};
}
4 changes: 2 additions & 2 deletions sutk/include/sutk/defines.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ namespace SUTK
u8 g;
u8 b;

constexpr Color3() noexcept : r(0), g(0), b(0) { }
constexpr Color3() noexcept : r(255), g(255), b(255) { }
constexpr Color3(u8 _r, u8 _g, u8 _b) noexcept : r(_r), g(_g), b(_b) { }

bool operator ==(Color3& rhs) const noexcept
Expand Down Expand Up @@ -389,7 +389,7 @@ namespace SUTK
};
u8 a;

constexpr Color4() noexcept : r(0), g(0), b(0), a(0) { }
constexpr Color4() noexcept : r(255), g(255), b(255), a(255) { }
constexpr Color4(u8 _r, u8 _g, u8 _b, u8 _a) noexcept : r(_r), g(_g), b(_b), a(_a) { }
constexpr Color4(u8 _r, u8 _g, u8 _b) noexcept : Color4(_r, _g, _b, 255) { }

Expand Down
35 changes: 35 additions & 0 deletions sutk/source/Geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ namespace SUTK
Geometry::Geometry(UIDriver& driver) noexcept : UIDriverObject(driver),
m_positionArrayInfo({ VertexPositionArray { }, false }),
m_indexArrayInfo({ VertexIndexArray { }, false }),
m_transformArrayInfo({ InstanceTransformArray { }, false }),
m_strokeInfo({ }),
m_fillColorInfo({Color4::white(), false }),
m_topology(Topology::TriangleList)
Expand All @@ -22,6 +23,7 @@ namespace SUTK
m_strokeInfo->isModified = false;
m_positionArrayInfo.isModified = false;
m_indexArrayInfo.isModified = false;
m_transformArrayInfo.isModified = false;
m_fillColorInfo.isModified = false;
return handle;
}
Expand Down Expand Up @@ -122,6 +124,39 @@ namespace SUTK
return *this;
}

Geometry& Geometry::instanceTransformArray(u32 transformCount) noexcept
{
auto& array = m_transformArrayInfo.array;

// ensure the requested size
array.reserve(transformCount);

// if lesser number of positions are requested, then we can decrease
// the size of position array from the end till its size becomes
// exactly as 'transformCount'
if(transformCount < array.size())
{
array.erase(array.begin() + transformCount, array.end());
_assert(array.size() == transformCount);
}

// if the number of already existing positions are lesser then
// add more elements at the end until the its size becomes exactly
// as 'transformCount'
while(array.size() < transformCount)
array.push_back({ });

m_transformArrayInfo.isModified = true;

return *this;
}

Geometry& Geometry::instanceTransform(InstanceTransform transform) noexcept
{
getInstanceTransformArrayForWrite().push_back(transform);
return *this;
}

Geometry& Geometry::lineStroke(LineStroke stroke, bool isDynamic) noexcept
{
if(!m_strokeInfo.has_value())
Expand Down
102 changes: 102 additions & 0 deletions sutk/source/RenderRectArray.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#include <sutk/RenderRectArray.hpp>
#include <sutk/RenderableContainer.hpp>
#include <common/assert.h> // for _com_assert()

namespace SUTK
{
RenderRectFillArray::RenderRectFillArray(UIDriver& driver, RenderableContainer* container) noexcept : GeometryRenderable(driver, container),
m_color(Color4::white()),
m_isColorDirty(true),
m_isActiveDirty(false),
m_isRectsDirty(true)
{
_com_assert(container != NULL);
// unit rect (1 centimeter by 1 centimeter)
Rect2Df rect = { 0, 0, 1.0f, 1.0f };
getGeometry()
.vertexPosition(rect.getTopLeft())
.vertexPosition(rect.getBottomLeft())
.vertexPosition(rect.getBottomRight())
.vertexPosition(rect.getTopRight())
.topology(Geometry::Topology::TriangleList)
.quad(0, 1, 2, 3)
.fillColor(getColor());
// we need to have at least one instance to create
getRectsForWrite().push_back({ 0.0f, 0.0f, 1.0f, 1.0f});

// call update for the first time as we have geometry description already and
// this geometry is supposed to be displayed in the very first frame.
update();
}

bool RenderRectFillArray::isDirty()
{
return m_isRectsDirty || m_isColorDirty || m_isActiveDirty;
}

void RenderRectFillArray::update()
{
if(m_isActiveDirty)
{
auto handle = getGfxDriverObjectHandle();
_com_assert(handle != GFX_DRIVER_OBJECT_NULL_HANDLE);
auto obj = getGfxDriver().getGeometryObject(handle);
getGfxDriver().setObjectActive(obj, isActive());
m_isActiveDirty = false;
}

if(m_isRectsDirty)
{
Geometry::InstanceTransformArray& transformArray = getGeometry().getInstanceTransformArrayForWrite();
transformArray.clear();
for(const Rect2Df& rect : m_rects)
{
Rect2Df _rect = getContainer()->getLocalCoordsToScreenCoords(rect);
transformArray.push_back(_rect);
}
}

if(m_isColorDirty)
{
getGeometry().fillColor(getColor());
}

if(m_isRectsDirty || m_isColorDirty)
{
GfxDriverObjectHandleType handle = getGfxDriverObjectHandle();
handle = getGeometry().compile(handle);
setGfxDriverObjectHandle(handle);
m_isRectsDirty = false;
m_isColorDirty = false;
}
}

void RenderRectFillArray::setActive(bool isActive) noexcept
{
// mandatory to call
GeometryRenderable::setActive(isActive);
m_isActiveDirty = true;
}

std::vector<Rect2Df>& RenderRectFillArray::getRectsForWrite() noexcept
{
m_isRectsDirty = true;
return m_rects;
}

void RenderRectFillArray::setColor(const Color4 color) noexcept
{
m_color = color;
m_isColorDirty = true;
}

void RenderRectFillArray::onGlobalCoordDirty() noexcept
{
m_isRectsDirty = true;
}

void RenderRectFillArray::onContainerResize(Rect2Df rect, bool isPositionChanged, bool isSizeChanged) noexcept
{
m_isRectsDirty = true;
}
}
58 changes: 55 additions & 3 deletions sutk/source/SGEGfxDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,10 @@ namespace SUTK

SGE::Shader SGEGfxDriver::compileShader(const Geometry& geometry)
{
return m_driver.getShaderLibrary().compileAndLoadShader(m_driver.getBuiltinFileData("/solid_color.v3dshader").first);
if(geometry.getInstanceTransformArray().size() > 0)
return m_driver.getShaderLibrary().compileAndLoadShader(m_driver.getBuiltinFileData("/solid_color_rect_array.v3dshader").first);
else
return m_driver.getShaderLibrary().compileAndLoadShader(m_driver.getBuiltinFileData("/solid_color.v3dshader").first);
}

std::pair<SGEMeshData, GfxDriverObjectHandleType> SGEGfxDriver::createMesh(const Geometry& geometry)
Expand All @@ -419,6 +422,12 @@ namespace SUTK
SGE::Shader shader = compileShader(geometry);
SGE::Material material = m_driver.getMaterialLibrary().createMaterial(shader, "Untittled");
material.set<vec4_t>("parameters.color", vec4(1.0f, 1.0f, 1.0f, 1.0f));
if(geometry.getInstanceTransformArray().size() > 0)
{
f32 z = SUTKToSGECoordTransform({ 1.0f, 0 }).z;
z += getSizeInPixels().x * 0.5f;
material.set<float>("parameters.numPixelsPerCM", z);
}
object.setMaterial(material);
object.attach(mesh);
// rebuild render pass graph as new objects have been added into the render scene
Expand Down Expand Up @@ -519,11 +528,11 @@ namespace SUTK
createInfo.binding = 0;

// if there is no vertex buffer then create one with binding equal to zero
if(mesh.getVertexBufferCount() == 0)
SGE::Buffer vertexBuffer = mesh.getVertexBuffer(0);
if(static_cast<void*>(vertexBuffer) == NULL)
mesh.createAndAddVertexBuffer(createInfo);
else
{
SGE::Buffer vertexBuffer = mesh.getVertexBuffer(0);
_assert(vertexBuffer.getTraits()->elementSize == createInfo.stride);
// if the existing vertex buffer's capacity is not equal to that of new number of posijtions
if(vertexBuffer.getTraits()->elementCount != positionArray.size())
Expand All @@ -539,6 +548,49 @@ namespace SUTK
}
}

if(geometry.isInstanceTransformArrayModified())
{
// convert vertex position array into SGE's coordinates and strides.
auto& transformArray = geometry.getInstanceTransformArray();
vec4_t data[transformArray.size()];
for(u32 i = 0; i < transformArray.size(); ++i)
{
Rect2Df rect = transformArray[i];
vec3_t pos = SUTKToSGECoordTransform(rect.getPosition());
vec3_t size = SUTKToSGECoordTransform(rect.getSize());
data[i] = { pos.z, pos.y, size.z, size.y };
}

mesh.setInstanceCount(static_cast<u32>(transformArray.size()));

// prepare the vertex buffer create info struct
SGE::Mesh::VertexBufferCreateInfo createInfo = { };
createInfo.data = data,
createInfo.stride = sizeof(vec4_t),
createInfo.count = transformArray.size(),
createInfo.binding = 5;

// if there is no vertex buffer then create one with binding equal to 5
SGE::Buffer vertexBuffer = mesh.getVertexBuffer(5);
if(static_cast<void*>(vertexBuffer) == NULL)
mesh.createAndAddVertexBuffer(createInfo);
else
{
_assert(vertexBuffer.getTraits()->elementSize == createInfo.stride);
// if the existing vertex buffer's capacity is not equal to that of new number of posijtions
if(vertexBuffer.getTraits()->elementCount != transformArray.size())
{
// then destroy the vertex buffer at binding = 0
mesh.destroyVertexBuffer(5);
// and create a new vertex buffer for the binding = 0
mesh.createAndAddVertexBuffer(createInfo);
}
// otherwise, just copy the new data
else
vertexBuffer.copyData(0, reinterpret_cast<void*>(data), sizeof(vec4_t) * transformArray.size());
}
}

return newHandle;
}

Expand Down

0 comments on commit 01e8edc

Please sign in to comment.