Skip to content

Commit

Permalink
#5584: Start implementing container classes storing the winding vertices
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Nov 6, 2021
1 parent d9ac2ae commit dd9d9b8
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 0 deletions.
40 changes: 40 additions & 0 deletions include/iwindingrenderer.h
@@ -0,0 +1,40 @@
#pragma once

#include <vector>
#include <limits>
#include "render/ArbitraryMeshVertex.h"

namespace render
{

/**
* A winding renderer accepts a variable number of windings and arranges them into
* one or more continuous blocks of vertices for efficient rendering.
*
* The internal arrangement has the goal of reducing the amount of draw calls for
* winding sharing a single material. Allocating a winding slot yields a handle which
* allows for later update or deallocation of the slot.
*
* Only the vertex data (XYZ, UV, Normals, Colour) needs to be submitted,
* the render indices of each winding slot are handled internally.
*/
class IWindingRenderer
{
public:
virtual ~IWindingRenderer() {}

using Slot = std::size_t;
static constexpr Slot InvalidSlot = std::numeric_limits<std::size_t>::max();

// Allocate a slot to hold the vertex data of a winding of the given size
// Returns the handle which can be used to update or deallocate the data later
virtual Slot allocateWinding(int size) = 0;

// Releases a previously allocated winding slot. This invalidates the handle.
virtual void deallocateWinding(Slot slot) = 0;

// Sets the winding data
virtual void updateWinding(Slot slot, const std::vector<ArbitraryMeshVertex>& vertices) = 0;
};

}
74 changes: 74 additions & 0 deletions libs/render/CompactWindingVertexBuffer.h
@@ -0,0 +1,74 @@
#pragma once

#include <vector>

namespace render
{

template<typename VertexT>
class CompactWindingVertexBuffer
{
private:
std::size_t _size;
std::size_t _numIndicesPerWinding;

std::vector<VertexT> _vertices;

// The indices suitable for rendering triangles
std::vector<unsigned int> _indices;

public:
CompactWindingVertexBuffer(std::size_t size) :
_size(size),
_numIndicesPerWinding(3 * (_size - 2))
{}

CompactWindingVertexBuffer(const CompactWindingVertexBuffer& other) = delete;
CompactWindingVertexBuffer& operator=(const CompactWindingVertexBuffer& other) = delete;

std::size_t getWindingSize() const
{
return _size;
}

std::size_t getNumIndicesPerWinding() const
{
return _numIndicesPerWinding;
}

const std::vector<VertexT>& getVertices() const
{
return _vertices;
}

const std::vector<unsigned int>& getIndices() const
{
return _indices;
}

// Appends the given winding data to the end of the buffer, returns the position in the array
std::size_t pushWinding(const std::vector<VertexT>& winding)
{
assert(winding.size() == _size);

auto currentSize = _vertices.size();
auto position = currentSize / _size;
_vertices.reserve(currentSize + _size); // reserve() never shrinks

std::copy(winding.begin(), winding.end(), std::back_inserter(_vertices));

// Allocate and calculate indices
_indices.reserve(_indices.size() + _numIndicesPerWinding);

for (unsigned int n = static_cast<unsigned int>(_size) - 1; n - 1 > 0; --n)
{
_indices.push_back(0);
_indices.push_back(n - 1);
_indices.push_back(n);
}

return position;
}
};

}
33 changes: 33 additions & 0 deletions libs/render/WindingRenderer.h
@@ -0,0 +1,33 @@
#pragma once

#include "iwindingrenderer.h"

namespace render
{

class WindingRenderer :
public IWindingRenderer
{
private:


public:
Slot allocateWinding(int size) override
{
// Get the Bucket this Slot is referring to

return InvalidSlot;
}

void deallocateWinding(Slot slot) override
{

}

void updateWinding(Slot slot, const std::vector<ArbitraryMeshVertex>& vertices) override
{

}
};

}
69 changes: 69 additions & 0 deletions test/WindingRendering.cpp
@@ -0,0 +1,69 @@
#include "gtest/gtest.h"
#include "render/ArbitraryMeshVertex.h"
#include "render/WindingRenderer.h"
#include "render/CompactWindingVertexBuffer.h"

namespace test
{

using VertexBuffer = render::CompactWindingVertexBuffer<ArbitraryMeshVertex>;

inline std::vector<ArbitraryMeshVertex> createWinding(int id, int size)
{
std::vector<ArbitraryMeshVertex> winding;

for (int i = 0; i < size; ++i)
{
winding.emplace_back(ArbitraryMeshVertex({ id + 0.0, id + 0.5, id + 0.3 }, { 0, 0, id + 0.0 }, { id + 0.0, -id + 0.0 }));
}

return winding;
}

inline void checkWindingIndices(const VertexBuffer& buffer, std::size_t slot)
{
// Slot must be within range
auto windingSize = buffer.getWindingSize();

EXPECT_LT(slot, buffer.getVertices().size() / windingSize);

// Assume the indices are within bounds
auto indexStart = buffer.getNumIndicesPerWinding() * slot;
EXPECT_LE(indexStart + buffer.getNumIndicesPerWinding(), buffer.getIndices().size());

// Check the indices, they must be referencing vertices in that slot
for (auto i = indexStart; i < indexStart + buffer.getNumIndicesPerWinding(); ++i)
{
auto index = buffer.getIndices().at(i);
EXPECT_GE(index, slot * windingSize) << "Winding index out of lower bounds";
EXPECT_LT(index, (slot + 1) * windingSize) << "Winding index out of upper bounds";
}
}

TEST(CompactWindingVertexBuffer, NumIndicesPerWinding)
{
for (auto i = 0; i < 10; ++i)
{
VertexBuffer buffer(i);
EXPECT_EQ(buffer.getWindingSize(), i);
EXPECT_EQ(buffer.getNumIndicesPerWinding(), 3 * (buffer.getWindingSize() - 2));
}
}

TEST(CompactWindingVertexBuffer, AddSingleWinding)
{
auto winding1 = createWinding(1, 4);

VertexBuffer buffer(4);

auto slot = buffer.pushWinding(winding1);

EXPECT_EQ(slot, 0) << "Wrong slot assignment";
EXPECT_EQ(buffer.getVertices().size(), 4);
EXPECT_EQ(buffer.getIndices().size(), buffer.getNumIndicesPerWinding());

// Assume that the indices have been correctly calculated
checkWindingIndices(buffer, slot);
}

}
1 change: 1 addition & 0 deletions tools/msvc/Tests/Tests.vcxproj
Expand Up @@ -114,6 +114,7 @@
<ClCompile Include="..\..\..\test\Transformation.cpp" />
<ClCompile Include="..\..\..\test\UndoRedo.cpp" />
<ClCompile Include="..\..\..\test\VFS.cpp" />
<ClCompile Include="..\..\..\test\WindingRendering.cpp" />
<ClCompile Include="..\..\..\test\WorldspawnColour.cpp" />
</ItemGroup>
<ItemGroup>
Expand Down
1 change: 1 addition & 0 deletions tools/msvc/Tests/Tests.vcxproj.filters
Expand Up @@ -52,6 +52,7 @@
<ClCompile Include="..\..\..\test\TextureManipulation.cpp" />
<ClCompile Include="..\..\..\test\EntityInspector.cpp" />
<ClCompile Include="..\..\..\test\UndoRedo.cpp" />
<ClCompile Include="..\..\..\test\WindingRendering.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\test\HeadlessOpenGLContext.h" />
Expand Down
1 change: 1 addition & 0 deletions tools/msvc/include.vcxproj
Expand Up @@ -197,6 +197,7 @@
<ClInclude Include="..\..\include\iundo.h" />
<ClInclude Include="..\..\include\iversioncontrol.h" />
<ClInclude Include="..\..\include\ivolumetest.h" />
<ClInclude Include="..\..\include\iwindingrenderer.h" />
<ClInclude Include="..\..\include\modelskin.h" />
<ClInclude Include="..\..\include\ModResource.h" />
<ClInclude Include="..\..\include\precompiled_interfaces.h" />
Expand Down
1 change: 1 addition & 0 deletions tools/msvc/include.vcxproj.filters
Expand Up @@ -162,6 +162,7 @@
<Filter>ui</Filter>
</ClInclude>
<ClInclude Include="..\..\include\imapfilechangetracker.h" />
<ClInclude Include="..\..\include\iwindingrenderer.h" />
</ItemGroup>
<ItemGroup>
<Filter Include="ui">
Expand Down
4 changes: 4 additions & 0 deletions tools/msvc/libs.vcxproj
Expand Up @@ -211,20 +211,24 @@
<ClInclude Include="..\..\libs\render\CamRenderer.h" />
<ClInclude Include="..\..\libs\render\Colour4.h" />
<ClInclude Include="..\..\libs\render\Colour4b.h" />
<ClInclude Include="..\..\libs\render\CompactWindingVertexBuffer.h" />
<ClInclude Include="..\..\libs\render\IndexedVertexBuffer.h" />
<ClInclude Include="..\..\libs\render\NopVolumeTest.h" />
<ClInclude Include="..\..\libs\render\RenderableCollectionWalker.h" />
<ClInclude Include="..\..\libs\render\RenderablePivot.h" />
<ClInclude Include="..\..\libs\render\RenderableSpacePartition.h" />
<ClInclude Include="..\..\libs\render\SceneRenderWalker.h" />
<ClInclude Include="..\..\libs\render\TexCoord2f.h" />
<ClInclude Include="..\..\libs\render\TextureToolView.h" />
<ClInclude Include="..\..\libs\render\VBO.h" />
<ClInclude Include="..\..\libs\render\VectorLightList.h" />
<ClInclude Include="..\..\libs\render\Vertex3f.h" />
<ClInclude Include="..\..\libs\render\VertexCb.h" />
<ClInclude Include="..\..\libs\render\VertexHashing.h" />
<ClInclude Include="..\..\libs\render\VertexNCb.h" />
<ClInclude Include="..\..\libs\render\VertexNT.h" />
<ClInclude Include="..\..\libs\render\View.h" />
<ClInclude Include="..\..\libs\render\WindingRenderer.h" />
<ClInclude Include="..\..\libs\RGBAImage.h" />
<ClInclude Include="..\..\libs\scenelib.h" />
<ClInclude Include="..\..\libs\selectionlib.h" />
Expand Down
12 changes: 12 additions & 0 deletions tools/msvc/libs.vcxproj.filters
Expand Up @@ -329,6 +329,18 @@
<ClInclude Include="..\..\libs\messages\MapOperationMessage.h">
<Filter>messages</Filter>
</ClInclude>
<ClInclude Include="..\..\libs\render\WindingRenderer.h">
<Filter>render</Filter>
</ClInclude>
<ClInclude Include="..\..\libs\render\CompactWindingVertexBuffer.h">
<Filter>render</Filter>
</ClInclude>
<ClInclude Include="..\..\libs\render\VBO.h">
<Filter>render</Filter>
</ClInclude>
<ClInclude Include="..\..\libs\render\IndexedVertexBuffer.h">
<Filter>render</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="util">
Expand Down

0 comments on commit dd9d9b8

Please sign in to comment.