Function Pointers

Started by
8 comments, last by Drew_Benton 19 years, 4 months ago
Ok, Ok I know you guys are probabally sick of me asking questions by now [lol]. Anyways I have done a lot of research on function pointers and their use. Unlike threads, they are a little more helpful for even the basic programs. This is what I have done:

.. Inside Game Loop ...
else
{
	BeginDraw();
	Update();
	Draw();
	EndDraw();
}
.. Inside Game Loop ...

.. Later in the file ..
void Immortal_Core::BeginDraw()
{
	if( m_renderer == RENDERER_SDL )
	{
		SDL_FillRect(m_screen,NULL,0x000000);
	}
	else if( m_renderer == RENDERER_OPENGL )
	{
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glLoadIdentity();
	}
}

void Immortal_Core::EndDraw()
{
	if( m_renderer == RENDERER_SDL )
	{
		SDL_Flip(m_screen);
	}
	else if( m_renderer == RENDERER_OPENGL)
	{
		glFlush();
		SDL_GL_SwapBuffers();		
	}	
}
.. Later in the file ..


And converted it to this:

.. Inside engine setup ..
if(m_renderer == RENDERER_SDL)
{
	ptBeginDraw = BeginDrawSDL;
	ptEndDraw = EndDrawSDL;
}
else if(m_renderer == RENDERER_OPENGL)
{
	ptBeginDraw = BeginDrawOGL;
	ptEndDraw = EndDrawOGL;
}
.. Inside engine setup ..


.. Later in the file ..
void Immortal_Core::BeginDraw()
{
	(*this.*ptBeginDraw)();
}

void Immortal_Core::EndDraw()
{
	(*this.*ptEndDraw)();
}
.. Later in the file ..


.. Later in the file ..
void Immortal_Core::BeginDrawSDL()
{
	SDL_FillRect(m_screen,NULL,0x000000);
}

void Immortal_Core::BeginDrawOGL()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glLoadIdentity();
}

void Immortal_Core::EndDrawSDL()
{
	SDL_Flip(m_screen);
}

void Immortal_Core::EndDrawOGL()
{
	glFlush();
	SDL_GL_SwapBuffers();
}
.. Later in the file ..

As you can see, I have made class member function pointers that tells the engine which set of functions to call - this way I am not calling if/else redudantly for a variable that will not change througout the game. My question for you all is does anyone have any comments about doing this - ie potential problems I might have. I feel really good about using this approach, because the end user can still overload the Begin/End draw functions and the engine will still work, the function pointers wont be used then, but they are not wasting any significant amount of space and memory. Would anyone advise against what I am doing, or do you think it is a good choice? Thanks again, and I promise I wont ask anymore questions until tomorrow [WINK].
Advertisement
C++ offers a better alternative to function pointers for what you are doing, and it is inheritance and polymorphism.

You should have an abstract renderer class that declares pure virtual methods BeginDraw and such. Then your opengl and sdl renderers will inherit from the base class and provide appropriate implementations to your methods.

Since you are using C++ anyway the function pointers are (almost) not necessary because you have virtual methods, inheritance and polymorphism.
Give a man a fish and you feed him for a day; teach him to use the Net and he won't bother you for weeks.
Quote:Original post by OrthoDiablo
C++ offers a better alternative to function pointers for what you are doing, and it is inheritance and polymorphism.

You should have an abstract renderer class that declares pure virtual methods BeginDraw and such. Then your opengl and sdl renderers will inherit from the base class and provide appropriate implementations to your methods.

Since you are using C++ anyway the function pointers are (almost) not necessary because you have virtual methods, inheritance and polymorphism.


I know what your saying, but that **is** my base class =). They way i have my engine is the abstract base class that contains all the necessary functions to provide a working framework. The way it is now, all you have to do is dervive a class from it and call the Run() function. That is all of what is needed to create a blank SDL or OpenGL window. Now if the user wanted to actually do stuff, they will dervive the Draw,Init,Deinit,and Update functions so they can place their own code. The Begin and End draw are functions I added to the base class to help take care of everything, the end user just has to worry about adding in game specific code, thats it. Furthermore the end user can dervive their own BeginDraw and EndDraw (as well as any function) so they can control what happens. The way I have it setup, I can easily add other renderers without having to rewrite any code, I just would have to add in the appropriate setup code, assign the function pointers, and add another enum video mode. I hope this makes sense. Thanks your for your input though, it is much appreciated.
While its a nice learning exerise I have to agree with OrthoDiablo and congratulate you on making a (slightly hackish) version of C++ inheritance with your own code.

The same could be achived via a base class and two derived classes from that. The base class would have your default draw/update/beginscene/endscene functions in and your direved classes would just overload/hide as needs be, much the same as you are already doing.
The only difference is that, in the setup instead of setting function pointers you'd create an instance of the right class and let C++ do the rest.

I also dont see how you'll be able to setup other renderers without having to write any code, as you've got path dependant code already which would need to be dealt with and thats no different from creating a new class, deriving as needed and using it when requested.

Dont get me wrong, you've got an intresting learning exercise here, but beyond that C++ can natively do what you are doing and maybe even slightly faster..
Quote:Original post by Drew_Benton
Quote:Original post by OrthoDiablo
C++ offers a better alternative to function pointers for what you are doing, and it is inheritance and polymorphism.

You should have an abstract renderer class that declares pure virtual methods BeginDraw and such. Then your opengl and sdl renderers will inherit from the base class and provide appropriate implementations to your methods.

Since you are using C++ anyway the function pointers are (almost) not necessary because you have virtual methods, inheritance and polymorphism.


I know what your saying, but that **is** my base class =). They way i have my engine is the abstract base class that contains all the necessary functions to provide a working framework. The way it is now, all you have to do is dervive a class from it and call the Run() function. That is all of what is needed to create a blank SDL or OpenGL window. Now if the user wanted to actually do stuff, they will dervive the Draw,Init,Deinit,and Update functions so they can place their own code. The Begin and End draw are functions I added to the base class to help take care of everything, the end user just has to worry about adding in game specific code, thats it. Furthermore the end user can dervive their own BeginDraw and EndDraw (as well as any function) so they can control what happens. The way I have it setup, I can easily add other renderers without having to rewrite any code, I just would have to add in the appropriate setup code, assign the function pointers, and add another enum video mode. I hope this makes sense. Thanks your for your input though, it is much appreciated.
definatly not the approach id use, defeats the some of the purpose of having a base interface.

// GameDev.net CodeBox Formatter By Danushka "Silvermace"
// http://www.unsoundminds.com/codeformat/
// render device interface
class IRenderDevice
{
public:
virtual void init() = 0;
virtual void addMesh( IMesh* mesh ) = 0;
virtual void renderAll() = 0;
};

// GL rendering device
class OpenGLRenderDevice : public IRenderDevice
{
public:
void init() {
SDL_Init( SDL_VIDEO | ... );
setUpProjectionMatrix();
setDefaultOpenGLStates();
}

void addMesh( IMesh* mesh )
{
if( mesh != NULL )
meshes.push_back( mesh );
}

void renderAll()
{
foreach( m in meshes )
renderMeshOpenGL( m );
}

};

something like that anyway..

Cheers,
-Danu
"I am a donut! Ask not how many tris/batch, but rather how many batches/frame!" -- Matthias Wloka & Richard Huddy, (GDC, DirectX 9 Performance)

http://www.silvermace.com/ -- My personal website
Quote:.. Later in the file ..
void Immortal_Core::BeginDraw()
{
(*this.*ptBeginDraw)();
}

void Immortal_Core::EndDraw()
{
(*this.*ptEndDraw)();
}
.. Later in the file ..


imho, i *think* (since i havent used func pointers in a while) the syntax here is more cryptic than necessary. correct me if i'm wrong but cant they just be written as:

this.ptBeginDraw() ..?
this.ptEndDraw() ..?

i believe my suggestion may not be syntactically conformant to actual c++ (or is it), but i've used it that way before within a class itself. hrm.. i wonder..?

[Edited by - CraZeE on December 15, 2004 12:46:23 AM]
- To learn, we share... Give some to take some -
ptBeginDraw();
ptEndDraw();

is fine...

"this" is only needed if ptBeginDraw or ptEndDraw is ambiguous...

also "(*this)." is the same as "this->"

- Steve
Quote:Original post by Anonymous Poster
ptBeginDraw();
ptEndDraw();
is fine...
"this" is only needed if ptBeginDraw or ptEndDraw is ambiguous...
also "(*this)." is the same as "this->"
- Steve


Yea I noticed that during recompile and fixed that [wink]

Quote:Original post by _the_phantom_
I also dont see how you'll be able to setup other renderers without having to write any code, as you've got path dependant code already which would need to be dealt with and thats no different from creating a new class, deriving as needed and using it when requested.


Well I didnt mean I wouldnt have to write any more code, just that adding in code would be a breeze. Lets say I wanted to add a DX mode, I would add a RENDERER_DX enum first. Next I would go to my SetupEngine() function and add in a if(m_renderer == RENDERER_DX){} in which I would add the setup code as well as assign the function pointer to BeginDrawDX and EndDrawDX, those 2 functions are added to make life easier for the end programmer. They are not even in the skeleton form of my engine, but for this version, I want the engine to be able to take care as much as possible for the user.

Quote:Original post by silvermace
definatly not the approach id use, defeats the some of the purpose of having a base interface.


I can see your point on the base class stuff, but consider this: If you were to use an engine, would you rather have a system like mine, where you select the rendering mode via a parameter in which the functionality is already part of the engine or having a multi-classes appraoch where you dervive the video component from a base video class and add that to the engine. These are just some ideas I thought of when writing this.

My overall goals were to make something very simple and maintainable (that is why i did not use multiple classes), but after discussing this, I will think of how I can incoperate the ideas presented with using a different method of the graphics layer. Ultimately, i would like the engine to use a "plugin" styled graphics where you can use a default renderer or make your own. That type of design would definitly require the ideas posted by you all, so I will begin thinking about that appraoch.

Thank-you everyone for taking the time to respond! I appreciate your ideas and responses to my craziness [lol]. There is a nice Plugin loading tutorial at flip code I think I will pay another visit to and make a separate design using that and a better inheritance model. Thanks again everyone!
what happens when you need to change the signature of your calling function?
or for that matter, what about when you need to add functionality?
or better yet.. try writing a direct3d renderer ;)
"I am a donut! Ask not how many tris/batch, but rather how many batches/frame!" -- Matthias Wloka & Richard Huddy, (GDC, DirectX 9 Performance)

http://www.silvermace.com/ -- My personal website
Quote:Original post by silvermace
// GameDev.net CodeBox Formatter By Danushka "Silvermace"
// http://www.unsoundminds.com/codeformat/


That is a neat little tool!

Quote:Original post by silvermace
what happens when you need to change the signature of your calling function?
or for that matter, what about when you need to add functionality?
or better yet.. try writing a direct3d renderer ;)


Yea I know what you mean, but I have done a DX/OGL renderer engine program before...omg it was horrible, I tried to figure out how to use WndProc in each class...*shivers*...

Yea I have begun working on a way to use that style you suggested. ive done it before, but I lost the code, so I will need to do it again, thanks!

This topic is closed to new replies.

Advertisement