0
\$\begingroup\$

I am writing graphics engine for educational pursoses and have some problems.

I need to have ability to use different vertex formats (for example position+normal+uv or position+normal+uv+bones+weights). I have different structs for these formats and have a class HardwareBuffer that stores OpenGL vertex and index buffers. The problem is to give this class the ability to work with different types of vertices. There are a way to make this class template and use like this:

HardwareBuffer<VertexPosNormUV> buffer;
buffer.addVertex(VertexPosNormUV(vector3(1, 1, 1), vector3(1, 0, 0), vector2(1, 0)));

But in my engine there is an interface IRenderer that have virtual method drawDataFromHardwaveBuffer. Also there is a class OpenGLRenderer that is inherited from it. And now I can't pass my hardware buffer object to this method because there isn't a way to use template virtual methods.

Renderer renderer = createRenderer(GraphicsDriver::OpenGL3);
renderer->drawDataFromHardwaveBuffer(buffer); // can't make this method template

I can write functions for every type of vertex but this is not a solution.

How can I solve the problem?

\$\endgroup\$
2
  • \$\begingroup\$ Some questions beforehand: - Which openGL version? - Aren't you using VBO's? \$\endgroup\$
    – MABVT
    Mar 6, 2018 at 20:29
  • \$\begingroup\$ I use OpenGL 3.3 and I use VBO for storing vertex data. \$\endgroup\$
    – Nikolai
    Mar 8, 2018 at 13:51

1 Answer 1

2
\$\begingroup\$

I'm not personally a fan of this architectural direction (giving the buffers strong vertex types and using runtime polymorphism in graphics abstractions). That said, a simple solution to this kind of problem is to hide the template argument by working with a base interface class.

In this solution your HardwareBuffer<T> type inherits from a BasicHardwareBuffer base, which provides the basic methods needed for the Renderer to use it. These basic methods are generally just ones that return a pointer to the buffer data (as a void* or similar), the size in bytes of the buffer, and some format enumeration that you can map to the underlying format enumeration for the concrete API.

In other words:

struct BasicHardwareBuffer {
  void* getBufferData();
  std::size_t getBufferSizeInBytes();
  BufferFormat getBufferFormat();
};

HardwareBuffer then is-a BasicHardwareBuffer:

template<typename VertexType>
struct HardwareBuffer : BasicHardwareBuffer {
};

drawDataFromHardwaveBuffer can take a pointer or reference to a BasicHardwareBuffer:

void Renderer::drawDataFromHardwaveBuffer(BasicHardwareBuffer& buffer) {
}

You can implement BasicHardwareBuffer's methods by requiring the child types pass information about the buffer size and format up from their own constructors:

HardwareBuffer<VertexType>::HardwareBuffer(std::size_t elementCount)
: BasicHardwareBuffer(elementCount * sizeof(VertexType), VertexType::Format) {
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .