4

I'm trying to find my ways in the C++ land and am increasingly confused by now. The toy application is a very basic OpenGL engine. So here's the (I guess simple) problem: I'd like to handle meshes of different vertex data, so I'd have e.g.

struct Vertex
{
    Vector3f position;
}

struct VertexN : public Vertex
{
    Vector3f normal;
}

Now I need a Mesh class, that holds the data and draws it. I've tried something like this:

template<class T>
class Mesh
{
    public:
        Mesh();
        ~Mesh();

        void load(const T * vertices, int num);
        void draw();

    protected:
        T * vertices_;

};

The different vertices have to be loaded and drawn differently and this can be done with template specialization.

My problem is that I like to have another class that holds instances of Mesh objects, but templated class members are obviously not allowed.

The other solution I can think of is to hold pointers to the base struct Vertex in Mesh, pass an identifier for the Vertex type used and then use switch statements in load() and draw() to allow for the different implementations.

What is the best way to accomplish this?

Any help is greatly appreciated.

bbtrb
  • 4,065
  • 2
  • 25
  • 30

3 Answers3

7

You can use inheritance and virtual functions. For example:

class MeshBase
{
public:
    virtual ~MeshBase() { }
    virtual void draw() = 0;
};

template <typename T>
class Mesh : public MeshBase
{
public:
    virtual void draw() { }
    // ...
};

With this approach, you can store pointers to the base class MeshBase in a container.

Ideally, you can use a pointer container, which will manage the pointers for you, or you can use a container of smart pointers (for example, a std::vector<std::shared_ptr<MeshBase> >, if your implementation includes shared_ptr; if not, it can be found in a number of places).

I would also recommend storing the vertices in a container in the Mesh class, rather than using manual dynamic allocation and memory management.

Community
  • 1
  • 1
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • could the template on Mesh also be removed given the inheritance of the Vertex classes? – drfrogsplat Jun 21 '10 at 15:09
  • @drfrogsplat: Only if you want to store pointers to individual vertices, which is probably not desired for performance reasons. I wouldn't use inheritance at all for a vertex class: just implement each type of vertex as an independent class or using a template (this is, for example, what OpenSceneGraph does). – James McNellis Jun 21 '10 at 15:11
  • 2
    Try to prefer `boost::ptr_vector` to `std::vector` if you have access to boost (it's part of Boost.PointerContainer). In C++0x, you could use `std::vector` to avoid the boost dependency. – Matthieu M. Jun 21 '10 at 15:14
  • @James: I knew the solution must be simple, thank you! I'll also remove the inheritance in the Vertex structs. About storing the vertices in std::vector: is it then still possible to access the different members of Vertex with the offsetof() macro? – bbtrb Jun 21 '10 at 15:47
  • @matthieu: yeah, learning boost is something on my todo list, I'll keep that in mind – bbtrb Jun 21 '10 at 15:49
  • @bbtrb: `offsetof()` only works on POD class types, so you can't use it on any classes that use inheritance, have private members, have virtual member functions, etc. – James McNellis Jun 21 '10 at 15:51
0

I recommend that you don't templatize your mesh class but make it capable of handling different types of vertex data. This is a common graphics problem and is addressed in DirectX with the notion of binding different "streams" of data together to draw geometry. In other words, your normals would be a different data stream than your position data. Then your mesh object becomes a container of multiple streams of data and would not be bound to a particular vertex format at compile time. I don't know OpenGL as well but I imagine there is a similar concept.

See: http://msdn.microsoft.com/en-us/library/bb147299(VS.85).aspx

bshields
  • 3,563
  • 16
  • 16
0

@bshields has a point, you need to represent vertex data in the most efficient manner, which in the case of OpenGL are Vertex Buffer Objects (VBOs): http://www.opengl.org/wiki/Vertex_Buffer_Object

Given the guidelines exposed in the link above - which go in line with what @James McNellis says about not using inheritance for your Vertex types - and the fact that both loading and drawing will probably depend on the type of vertex and the kind of input (or output) I would suggest you to apply the Strategy pattern using static polymorphism, as outlined in the answer to this other question: template strategy pattern

Community
  • 1
  • 1
Miquel Ramirez
  • 543
  • 2
  • 6
  • Thanks. draw() uses already a wrapper to VBOs. I should also align the data properly... The post you linked is interesting, but it looks like overkill for me right now. Bookmarked anyway. – bbtrb Jun 21 '10 at 15:55