Archived

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

A Problem for the Gurus (maybe)

This topic is 5576 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

Hi all, I''m trying to figure out how to solve this little problem. I''m trying to do a cross-api renderer, with GDI, OpenGL and Direct3D 8. I have a CRenderer Class, with a variable, Renderer. What I want to do is to be able to call: Renderer.SetMode(640,480,32); ... and have it be handled by the correct API sub-structure, may it be COGL, CD3D, or CGDI classes. Also, I want those to have inner access to CRenderer''s variables. So, a little example, if I have Renderer.API set to OpenGL, whenever I do Renderer.SetMode, it gets handled by COGL.SetMode Now, I could do this using pointers, I guess, but using pointers to methods can get really messy really fast, and this method does not allow me to have access to the parent class'' inner variables. It would be cool if I had a base class structure, like CAPI_Base, that all other classes would mimic (COGL, CD3D & CGDI). I would have a null variable, API, in my CRenderer Class, and then all i would have to do would be: if(Renderer.TargetAPI==OPENGL) {Renderer.API=COGL; }; and then if I called: Renderer.API.SetMode(640,480,32); ... I would be calling OpenGL''s methods, right? I Hope someone out there got the picture, thanx for listening,

[Hugo Ferreira][Positronic Dreams][Stick Soldiers]
"Redundant book title: "Windows For Dummies".
"Camouflage condoms: So they won''t see you coming".

Share this post


Link to post
Share on other sites
Perhaps you could use a base class(CRender for instance) with virtual member functions. Derive child classes from this base class which implement OGL and DirectX specific code for the virtual functions(COGL_Render and CDX_Render for instance).

In your main app use a pointer to the base class

CRender *pRender_Object = new COGL_Render;

or

CRender *pRender_Object = new CDX_Render;

then any call to pRender_Object->SetMode would use the OGL or DX code.

I''m not sure if this is the best idea but it seems to work for me.

Share this post


Link to post
Share on other sites
I agree with rhysj also, and to expand a little on what he said - here is some (pseudo) source code:


      
// Base class

class IRenderer
{

public:
// Note that no implementation is required for pure virtual functions

virtual bool Init( ) = 0;
virtual bool End( ) = 0;
virtual int SetMode( int, int, int ) = 0;

};

// D3Drenderer

class D3DRenderer : public IRenderer
{

public:
virtual bool Init( ); // provide implementation for these in .cpp file

virtual bool End( );
virtual int SetMode( int, int, int );
}


// opengl rendererd

class OGLRenderer : public IRenderer
{

public:
virtual bool Init( ); // provide implementation for these in .cpp file

virtual bool End( );
virtual int SetMode( int, int, int );
}


obviously, those classes should be split up into their respective header files. now in your program you can do:



  
IRenderer *renderer;

if ( mode = OPENGL )
renderer = new OGLRenderer;

if ( mode = DIRECTX )
renderer = new D3DRenderer;


renderer.SetMode( 800, 600, 32 );




hope this helps a little

jx

[edited by - Jx on August 28, 2002 7:28:20 AM]

[edited by - Jx on August 28, 2002 7:28:52 AM]

Share this post


Link to post
Share on other sites
ditto

---
Make it work.
Make it fast.

"I’m happy to share what I can, because I’m in it for the love of programming. The Ferraris are just gravy, honest!" --John Carmack: Forward to Graphics Programming Black Book

Share this post


Link to post
Share on other sites
Please note that there is a very small error in the code i posted.

the line:



renderer.SetMode( 800, 600, 32 );



should read:



renderer->SetMode( 800, 600, 32 );



note that the "." has been replace by a "->"

Share this post


Link to post
Share on other sites
ok, i got that one nailed down, but the net part also
goes way over my head. I''ve been searching the net for
polymorphism and pointers and can''t find an answer to this:

In my CWindow class, I have pointers to functions:

  void (*Event_Create) (void);
void (*Event_Destroy) (void);
void (*Event_Paint) (CWindow * ptr);
void (*Event_Size) (CWindow * ptr);
void (*Event_Move) (CWindow * ptr);

In the case one of these events fires, a standard handler
takes care of it, but if the pointer is not null, then the
handler call the function pointed to by the apropriate pointer.
If the user resizes the window, for example, there is a certain
template code that runs, but if i want something diferent done,
I change Event_Size:

  Event_Size() = size_handling_function();  


Now comes the tricky part. I want certain methods inside my
CRenderer class to handle window resizing. For this to work
I will have to get CWindow to call the apropriate metho inside
CRenderer. I was thinking of doing something in the style of:

  CWindow.Event_Size() = CRenderer.event_size();  

But his does not work. Using my current architecture, or
advising on how to change it, could someone tell me how to
get around this one?




[Hugo Ferreira][Positronic Dreams][Stick Soldiers]
"Please Review my WebSite!".

Share this post


Link to post
Share on other sites
First off, I don''t know if this was a typo or not, but you''re assigning the function pointers incorrectly. For instance...

Event_Size() = size_handling_function() 


should look like

Event_Size = size_handling_function 


but I''m assuming it was a typo because the former will almost certainly produce a compiler error.

As for you''re question, I''m a little confused as to what the trouble is. Can you not simply call CRenderer.event_size() from within the function body of CWindow.Event_Size(), or is there some aspect I''m missing? Also, if you have Visual Studio .NET you might want to check out the __event/__hook/__unhook keywords.

Share this post


Link to post
Share on other sites
Edit:
Maybe I misunderstood... function pointers are different:
class foo{
void (*function)(void);
};

void (*mypointerfunc)(void)
mypointerfunc = foo::function;

I think that's what you want.

Use virtual functions,
putting "= 0;" makes it a pure virtual function that MUST be overridden but a deriving class. If you want to make some functions optionally overridable, don't put the equal zero part, then you have to define a function that the base class will call if the deriving class doesn't implement a new version.


    
class CRender{
virtual void Resize(int x, int y);
};
void CRender::Resize(int x, int y){
// do some default action

}

class NORender : CRender {
// resize is inherited, and the base class will be called.

};

class DXRender : CRender {
// resize is overridden and will be handled by the new definition.

virtual void Resize(int x, int y);
};




___________________________
Freeware development:
ruinedsoft.com

[edited by - iwasbiggs on September 9, 2002 9:17:06 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by pentium3id
I want to, from within a class' method, call another
class' method, using a method pointer.

Your pointer must be declared to be off secondclass type:
void (*CRender::func)(CWindow *);   

This makes it difficult to use non-class functions with the same pointer/handler. (The reason why is that non-class methods and member methods have different calling conventions - __stdcall/__cdecl vs __thiscall). You might be able to solve this using binders:

CRender::ResizeWindow( CWindow * wnd, int x, int y )
{
wnd->Resize(x, y);
}

...
CRender * r = appropriate_class();
wnd.Event_Size = trinary_mem_function( CWindow *, int, int, r );

In the above snippet, trinary_mem_function is a custom adapter that takes the three argument types for a member function and an object off which the member function will be called, allowing you to call the member function as if it were a global function.

Not trivial, not pretty.

The most robust solution I can think of, however, is to use function objects (classes that overload operator ()), because these will make no difference whether they are class members or global objects.

class Resizer
{
void operator () (CWindow * wnd, int x, int y)
{
wnd->Resize(x, y);
}
};
 
class SomeClass
{
private:
Resizer myResizer;
};


[edited by - Oluseyi on September 9, 2002 8:24:33 PM]

Share this post


Link to post
Share on other sites