Sign in to follow this  

[C++] Advice on design: render and texture classes tighly bond

This topic is 2785 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm having slight trouble getting the design right for a part of my GUI library. It is supposed to support multiple renderers, therefore theres is a renderer base class from which, for example, Renderers::OpenGL inherits. All renderers can draw quads through the quad() method (either coloured, textured or both). Some quads (most actually) will contain textures. Textures are derived from a base class texture. For example Textures::OpenGL inherits from this base class. Now, only Renderers::OpenGL can render Textures::OpenGL textures. No DirectX or SDL textures, only OpenGL textures. So what I did, initially, was this: - library-user creates a Renderer instance (lets say: a Renderers::OpenGL instance) - whenever he allocates some texture through the library, he passes the renderer. Each renderer has an overloaded Texture-factory member function to create an instance of the right type of texture, in our example Textures::OpenGL - widgets using this texture, will, when they need to be drawn, call the quad() method of the renderer and pass the coordinates, colour and texture of a quad - the renderer will render the quad, but, to be sure that the passed texture is an Textures::OpenGL, theres is a check with dynamic_cast After futher investigation this didn't seem like a well designed system. The dynamic_cast is costly; I could make an enum with all texture types and check that for each texture passed, not sure if this is better / quicker. I could also just perform a static_cast and let the library user be responsible (aft5er all, he is the one passing a widget with the wrong kind of texture)... One solution that came to mind is this: perhaps I shouldn't care about the kind of texture and just let the texture render itself (some method in the texture class similar to quad() from the renderer). But with some optimization variables in the renderer class, the texture class would need to be the friend of the renderer class (to access the private variables). This way I also need to pass the renderer pointer / reference to the texture, but then the same problem appears (is this an OpenGL renderer or some other one?). I rather have the drawing handled at the renderer itself, where the renderer uses the texture, in which case the possibilities are: - dynamic_cast the texture to make sure it fits with the renderer - check upon some enum ID whether the texture fits with the renderer - static_cast and have responsibility at the library-user - completely redesign the system Any ideas? I'm at the uni atm, so I'll post some concrete code when needed. Thanks in advance! [Edited by - Decrius on April 27, 2010 11:46:22 AM]

Share this post


Link to post
Share on other sites
Have you considered polymorphism? In general, when you are checking types at runtime, you will probably want to refactor so that you can use polymorphism instead.
Another option is custom RTTI, which might be less costly.
Try to refactor your code so that the type of the texture is specified at compile time, maybe use templates to do this.

Share this post


Link to post
Share on other sites
Both the renderer classes and texture classes are polymorph (the base class has virtual methods). This would be used in the example I sketched to let the texture classes have a quad() method too, to render themselves, but this increases the complexity somewhat...

Quote:
Original post by gtdelarosa2
Try to refactor your code so that the type of the texture is specified at compile time, maybe use templates to do this.


Yes, thanks, this is also what Antheus proposed to use templates. Could you clarify this / write a quick example? I don't immediately see how this could be used well...

Share this post


Link to post
Share on other sites
I think this example below describes the problem well:

class Foo
{
public:
};

class Foo1: public Foo
{
public:
};

class Foo2: public Foo
{
public:
};

class Bar
{
public:
virtual void f(const Foo &foo) = 0;
};

class Bar1: public Bar
{
public:
/*void f(const Foo &foo)
{
std::cerr << "Bar1::f(const Foo &);\n";
}*/


void f(const Foo1 &foo) // only want Foo1
{
std::cerr << "Bar1::f(const Foo1 &);\n";
}
};

class Bar2: public Bar
{
public:
/*void f(const Foo &foo)
{
std::cerr << "Bar1::f(const Foo &);\n";
}*/


void f(const Foo2 &foo) // only want Foo2
{
std::cerr << "Bar1::f(const Foo2 &);\n";
}
};



Where Foo1 and Bar1, as well as Foo2 and Bar2 are bond. Foo is the texture class, Bar the renderer. Maybe this clarifies it a bit.

Share this post


Link to post
Share on other sites
The way I "solved" this was to use the renderer as a factory, and then design its interface so I didn't actually have to pass the objects back in. Mine is slightly higher-level than yours, so it might not work the same in your situation. But you could return integer id's mapped to an internal registry of textures or something like that. Basically, the renderer knows its own.

Here's a page I wrote about it in my project: clicky. You can get the gist of it just from the first code listing. SetTrackable is the only function that needs to check its argument for correctness, and there I just compared it to the pointers already in the list. The rest of the communication happens behind the scenes.

Share this post


Link to post
Share on other sites

This topic is 2785 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this