Archived

This topic is now archived and is closed to further replies.

_the_phantom_

Thoughts on renderer 'classes'

Recommended Posts

While reading the OOP in games thread below someone mentioned that doing OOP doesnt always mean using classes, and this tripped off a little thought in my head regarding game writing. Most ppl will, as they progress, make a renderer class to deal with all the rendering. However, what if you didnt do that, what if instead you placed all your rendering calls into a namespace instead of a class? From first thoughts there doesnt seem to be any reason why you couldnt do this and have it work just as well. Any infomation you want hidden from the calling functions can be hidden in an anon namespace inside the file. The same can be said of function you dont want the outside world to see as well. So, much like a class you are only exposing the interface you want the other functions to use/see and hiding the rest of the system behind it. Any thoughts/comments on this idea? Do you think its workable with any advantages/disadvantages i've not seen? (I've only just thought this up so i might have missed a few issues) [edited by - _the_phantom_ on October 22, 2003 11:07:30 PM]

Share this post


Link to post
Share on other sites
a lot of people (myself included) design their renderers to be pluggable, in so far as you have an abstract base class and then perhaps an OGL renderer or a D3D renderer. Having functions in a namespace wont give you that functionality at all.

i think a renderer is one of those things that does belong in a class, but things like math functions dont.

Share this post


Link to post
Share on other sites
Seeing as I wrote that comment in the other thread, it shouldn''t come as a surprise that that''s the path I take.

It''s just that, I prefer rnd::renderScene() to something like CRenderer::GetSingletonPtr()->renderScene() ... and don''t laugh at that example, because it''s exactly the kind of code that''s used in the glorified Enginuity set of articles (not to downplay the importance of the articles, I just dislike the syntax).

Now, maybe for large commercial projects, having base classes might be a smarter thing to do. I can see the benefit there. But does it have to be "inheritable" to be re-usable? I can''t see why you can''t take a set of functions and add to them.

- Ben

Share this post


Link to post
Share on other sites
With an abstract base renderer class you can support multiple rendering apis by creating an instance of the renderer class you wish to use. This inherited renderer class can even be created by a dynamic library, this gives even more flexibility. Quake 2 did this, same for half-life.

I agree with you that the interface for that singleton is ugly:

CRenderer::GetSingletonPtr()->renderScene()

I wonder why they don''t simply return a reference to the singleton object instead of a pointer. I also wonder why they didnt bother making at least a definition of the renderer to hide the singleton calls, or even create a global pointer to it.
Personally, I find that singletons are a waste... You just have to create one instance and avoid creating others, works fine.



Looking for a serious game project?
www.xgameproject.com

Share this post


Link to post
Share on other sites
quote:
Original post by jonnii
a lot of people (myself included) design their renderers to be pluggable, in so far as you have an abstract base class and then perhaps an OGL renderer or a D3D renderer. Having functions in a namespace wont give you that functionality at all.



Ok, but look at it this way, you've still got a common interface, yes?
Its just the underlaying system which has changed the data still has to be passed down the same way, so you could still have your class under the namespace, via a factory to select the right class to create, but only have the name space functions avalible to the outside world


namespace mygfxsystem
{
namespace
{
RenderClass * myrender;
// any other private data required

}
void Draw(Object *myobject)
{
RenderClass->Draw(myobject);
}
}


Ok, i admit that its a simple example, however given that the Draw call should be inlined you arent losing anything at all vs the current system speedwise but i just feel that mygfxsystem::Draw(data); is easier to work out then CRender::GetRender()->Draw(data);

Any yep Basiror i do realise that this does smack somewhat of the C-style way of doing things, however now i think about it does make as much sense conceptualy as objects.

Certainly if you only plan on supporting one API this could be an effective method (unless i can spot any serious flaws in this method I plan to use it with the OpenGL engine i'm planning to write).

Edit:
In response to the above post, you dont even really need a singleton, as the rest of the system doesnt need to see anything beyond the namespace (which you cant create an instance of anyways) and that namespace will control all access/creation of the gfx objects


[edited by - _the_phantom_ on October 23, 2003 2:35:21 PM]

Share this post


Link to post
Share on other sites
In the same vain tho you could just use static methods and go something like

CRenderClass::Draw(Object o);

I dont see the point of hiding things in namespaces, and it doesnt stop people from using the child namespace and calling the methods directly...

Share this post


Link to post
Share on other sites
quote:
Original post by _the_phantom_
Most ppl will, as they progress, make a renderer class to deal with all the rendering.
However, what if you didnt do that, what if instead you placed all your rendering calls into a namespace instead of a class?

From first thoughts there doesnt seem to be any reason why you couldnt do this and have it work just as well.
Any infomation you want hidden from the calling functions can be hidden in an anon namespace inside the file.
The same can be said of function you dont want the outside world to see as well.
So, much like a class you are only exposing the interface you want the other functions to use/see and hiding the rest of the system behind it.

Any thoughts/comments on this idea? Do you think its workable with any advantages/disadvantages i''ve not seen?
(I''ve only just thought this up so i might have missed a few issues)


Because then you can''t change your rendering type at runtime. The concept of having a base type is that the two different renderers (IE an opengl implementation and a direct3d implementation) can be created and switched at runtime and just refered to using the same pointer. This way, you can create a new renderer type (inheriting from the base type) and you can switch between it and other renderers at runtime without having to change any other code. If you wanna take it further, this even allows you to completely put your rendering code into separate DLLs (which create instances of child renderers) and you main executable code has to be changed despite you being able to make an infinite amount of renderers, all which can be switched between at runtime.

Share this post


Link to post
Share on other sites
quote:
Original post by jonnii
I dont see the point of hiding things in namespaces, and it doesnt stop people from using the child namespace and calling the methods directly...



it does if they are anon namespaces as they arent viewable outside of the namespace.

And i cant help but thing there is a flaw with the ''make the functions static'' idea, but atm i cant put my finger on it (blame the vodka).. if i can i''ll come back to that point..

Share this post


Link to post
Share on other sites
quote:
Original post by Polymorphic OOP
Because then you can''t change your rendering type at runtime.


errm, yes you can.... see my example above where you have an anon namespace internal to the mygfxsystem namespace.
With either method you need a factory system to make the instance of the correct class (mygfxsystem::init("OpenGL") and off the top of my head i cant think how you''d do it for a singleton system), and the class would still derive (sp?) from a common base class but would be totaly hidden from the external world.
You now have no global objects in play as the render is hidden away inside a namespace and everything just seems a bit cleaner to my way of thinking.


// following on from above

#include "mygfxsystem.h"
int main()
{
mygfxsystem::init("opengl"); // init the renderer system for opengl

// other code

}

void myobject::somefunction()
{
mygfxsystem::draw(mydata); // ask the gfx system to draw your data

// other code

}


(again, my example might not be that great but you get the idea)

Share this post


Link to post
Share on other sites
quote:
Original post by _the_phantom_
the class would still derive (sp?) from a common base class but would be totaly hidden from the external world.

So you DO have a base class -- your first post made it sound like you were not using a base class at all. Your argument then isn't about using namespaces instead of classes for a renderer, it's just should you use a namespace or a singleton to encapsulate the pointer used to interface with the current renderer.
quote:
Original post by _the_phantom_
You now have no global objects in play as the render is hidden away inside a namespace and everything just seems a bit cleaner to my way of thinking.


This is really just a matter of "globals vs global access singletons" and it really comes down to what you personally prefer. Remember that not all singletons have to be globally accessable from all objects (in fact, to be safe, they really shouldn't be), and, particularly here, it would be better off NOT as globally accessable. For instance, not everything in your game should be able to construct and reconstruct the singleton with different renderer types. Only one particular class should be able to perform these operations (or function, if you're not into pure OOP design). If you really want to go with strict design, as I personally would suggest, you wouldnt have ANY part of the singleton be globally accessable from all types -- make it have a single friend which is the only class which manages construction and destruction of the object and have that class delegate references to the instance to any objects which need to perform drawing. This gives you extremly modular design while limitting reliance on global data and even restricts access to only the type which manages the singleton. Remember, you don't use a singleton as a replacement for globals, if you do, then you don't fully understand the concept of a singleton. You use a singleton to limit the instances of the type to one, whether or not there is global access to the instance is another matter. You should try to limit access as much as you can.
Again, all of this comes down to opinion. If you take the singleton approach you can make much of the improper use of your objects literally impossible to do because syntactically it would be invalid do to access restriction. By not using a singleton, you lose this benefit and just rely on documentation to tell users what they should and shouldn't do, but improper use becomes completely valid syntactically. In general, it's safer to take the singleton approach.

Edit:

quote:
With either method you need a factory system to make the instance of the correct class (mygfxsystem::init("OpenGL") and off the top of my head i cant think how you'd do it for a singleton system), and the class would still derive (sp?) from a common base class but would be totaly hidden from the external world.


With a singleton system, and even without a singleton, if you aren't putting your renderers in DLLs, you can just make your "init" function templated. I don't recommend making it take a const char pointer.

Example:


template< typename RelatedType_t >
RelatedType_t* init()
{
delete Instance;
Instance = new RelatedType_t;
return static_cast< RelatedType_t* >( Instance );
}


Now you can do, IE:
init< Direct3d >();
or
init< OpenGL >();

The same logic goes for singletons, except you can even abstract it to a singleton base type so that you don't have to redefine the function for all your singletons.

[edited by - Polymorphic OOP on October 23, 2003 11:31:01 PM]

Share this post


Link to post
Share on other sites
Quote:
"Because then you can''t change your rendering type at runtime. The concept of having a base type is that the two different renderers (IE an opengl implementation and a direct3d implementation) can be created and switched at runtime and just refered to using the same pointer. This way, you can create a new renderer type (inheriting from the base type) and you can switch between it and other renderers at runtime without having to change any other code."

What, the thought of rnd::switchToOpenGL() never crossed your mind?

Share this post


Link to post
Share on other sites
I personally only use namespaces to demark internal classes/structs/functions and variables. This way, anyone trying to use my "engine" (i get so tired of calling it that) knows they must not access those within the EINTERNAL namespace. Although, I agree with carb that namespace''s seem somehow neater - although I could argue that static class methods and variables have exactly the same notation as namespaces. Oh, well, each to his own I suppose... :D

Share this post


Link to post
Share on other sites
I think the greatest point of all is: if you had stopped thinking about this stuff already, you just might have been done whatever it is you were trying to accomplish. Never know

Share this post


Link to post
Share on other sites
Well, since you asked for opinions, here''s mine: using namespaces instead of classes seems a bit off considering that classes are really just specialized namespaces to begin with. Think about it. A class is a collection of data and functions with specified rules for setting up access privileges to those data and functions. Using internal namespaces to achieve the same effect as making something private in a class seems a bit redundant to me. Namespaces are meant to be used to ensure that there are not conflicts between code in multiple libraries/projects. Why not use the features of the language the way they were meant to be used? Yes, a collection of math functions are a good candidate for collection inside of a namespace, but only to avoid conflicts with functions in other packages/libraries that will likely have the same names. Any time you have something that has state and specific actions to affect/use that state, you have an object and that''s what classes are for, e.g a renderer.

peace and (trance) out

Mage

Share this post


Link to post
Share on other sites