Page 1 of 1

Writing a program framework. Classes and stuff.

Posted: Sat Aug 04, 2007 6:39 am
by AndrewAPrice
I'm writing a game framework. I am using my own classes as wrappers around DirectX (and at a later point, OpenGL) classes.

Anyway, say my texture class contains the private member "IDirect3DTexture9 *m_d3dTexture;" (a Direct3D texture). This is defined in my header file which is included in the framework project and also end projects wishing to access my texture class.

But, the problem lies within abstracting my framework away from Direct3D. For an end program to include my texture.h they must have d3d9.h and d3dx9.h on their system (for IDirect3DTexture9) which means they must have the DirectX SDK installed on their system. I want to avoid this. I have virtually every game framework/engine do this (you don't need any DX or OpenGL SDK installed, just the link with the engine's dynamic library).

I do not want to have to convert every DirectX specific member to void * and then refer to them as ((IDirect3DSomeClass)myMember) everywhere in my code.

Re: Writing a program framework. Classes and stuff.

Posted: Sat Aug 04, 2007 9:19 am
by Candy
MessiahAndrw wrote:I do not want to have to convert every DirectX specific member to void * and then refer to them as ((IDirect3DSomeClass)myMember) everywhere in my code.
class XYZ;

class A {

XYZ *something;
XYZ &func(XYZ &something);
};

You don't need the declaration for XYZ to get this to work. Just forward declare it.

Re: Writing a program framework. Classes and stuff.

Posted: Sat Aug 04, 2007 5:56 pm
by AndrewAPrice
Candy wrote:
MessiahAndrw wrote:I do not want to have to convert every DirectX specific member to void * and then refer to them as ((IDirect3DSomeClass)myMember) everywhere in my code.
class XYZ;

class A {

XYZ *something;
XYZ &func(XYZ &something);
};

You don't need the declaration for XYZ to get this to work. Just forward declare it.
How about for structures?

Re: Writing a program framework. Classes and stuff.

Posted: Sun Aug 05, 2007 12:42 pm
by Candy
MessiahAndrw wrote:
Candy wrote:
MessiahAndrw wrote:I do not want to have to convert every DirectX specific member to void * and then refer to them as ((IDirect3DSomeClass)myMember) everywhere in my code.
class XYZ;

class A {

XYZ *something;
XYZ &func(XYZ &something);
};

You don't need the declaration for XYZ to get this to work. Just forward declare it.
How about for structures?
struct XYZ;

Did you at least try that?

Posted: Sun Aug 05, 2007 12:56 pm
by Kevin McGuire
Thats about the reason why I generally tend to not ask questions unless the question is about something that is:
  • Above my ability to mentally manipulate/conceptualize/understand.
  • Lacks any method to determine such as:
    • Pseudo/Partial Random Experimentation; changing inputs to determine effect on outputs.
    • Researching for existing solutions.
    • Isolation of a problem from the solution by removing/verifying surrounding parts.
The exception is if I am in a production environment where it is more beneficial to ask a question that I can or might be able to figure out myself, but do not know the answer to. Since it would cause a loss of production that would not be worth the profit from actually following what I said above.

Posted: Mon Aug 06, 2007 5:11 am
by AndrewAPrice
Are classes are just really structures except with methods?

Could I have:

private-header.h:

Code: Select all

class MyClass
{
public:
  // constructor and methods here
private:
  int someMember;
  IDirect3DDevice9 *superHiddenMember;
  int someOtherMember
};
and in:

public-header.h:

Code: Select all

class MyClass
{
public:
  // constructor and methods here
private:
  int someMember;
  int someOtherMember
};
So I don't need to define IDirect3DDevice9. Do I even need to include the private methods in my public header at all?

Posted: Mon Aug 06, 2007 7:43 am
by os64dev
You should problably look into the abstract factory pattern. consider the following code fragment. It defines an abstract class line and a pure virtual method to draw itself.
Next it define 3 line classes for Vesa, DrawDib and OpenGL with draw the line using the methods available for each interface.

then you have three factories GUIVesaFactory, GUIDrawDibFactory and GUIOpenGLFactory which allow us to create the Line object(and other objects ofcourse) for the above mentioned classes.

then finally there is the abstract factory GuiFactory which gets the appropriate factory via a name.

Code: Select all

#include <stdio.h> 
#include <string.h> 

typedef class Line { 
    protected:  int _x1, _y1, _x2, _y2; 
    public:     Line(int x1, int y1, int x2, int y2) : _x1(x1), _y1(y1), _x2(x2), _y2(y2) {} 
    public:     virtual void draw(void) = 0; 
} Line; 

typedef class DrawDibLine : public Line { 
    public:     DrawDibLine(int x1, int y1, int x2, int y2) : Line(x1, y1, x2, y2) {} 
    public:     virtual void draw(void) { 
                    printf("DrawDib::Line(%d, %d)-(%d, %d)\n", _x1, _y1, _x2, _y2); 
            } 
} DrawDibLine; 

typedef class OpenGLLine : public Line { 
    public:     OpenGLLine(int x1, int y1, int x2, int y2) : Line(x1, y1, x2, y2) {} 
    public:     virtual void draw(void) { 
                    printf("OpenGL::Line(%d, %d)-(%d, %d)\n", _x1, _y1, _x2, _y2); 
            } 
} OpenGLLine; 

typedef class VesaLine : public Line { 
    public:     VesaLine(int x1, int y1, int x2, int y2) : Line(x1, y1, x2, y2) {} 
    public:     virtual void draw(void) { 
                    printf("Vesa::Line(%d, %d)-(%d, %d)\n", _x1, _y1, _x2, _y2); 
            } 
} VesaLine; 

typedef class GUIFactory { 
    public: static  GUIFactory *    GetInstance(char *); 
    public: virtual Line *          CreateLine(int x1, int y1, int x2, int y2) = 0; 
} GUIFactory; 

typedef class GUIDrawDibFactory : public GUIFactory { 
    public: virtual Line *          CreateLine(int x1, int y1, int x2, int y2) { 
        return(new DrawDibLine(x1, y1, x2, y2)); 
    } 
} GUIDrawDibFactory; 

typedef class GUIOpenGLFactory : public GUIFactory { 
    public: virtual Line *          CreateLine(int x1, int y1, int x2, int y2) { 
        return(new OpenGLLine(x1, y1, x2, y2)); 
    } 
} GUIOpenGLFactory; 

typedef class GUIVesaFactory : public GUIFactory { 
    public: virtual Line *          CreateLine(int x1, int y1, int x2, int y2) { 
        return(new VesaLine(x1, y1, x2, y2)); 
    } 
} GUIVesaFactory; 

GUIFactory * GUIFactory::GetInstance(char * type) { 
    if(type != 0) { 
        if(strcmp(type, "DrawDib") == 0) { 
            return(new GUIDrawDibFactory); 
        } 
        else 
        if(strcmp(type, "OpenGL") == 0) { 
            return(new GUIOpenGLFactory); 
        } 
        else 
        if(strcmp(type, "Vesa") == 0) { 
            return(new GUIVesaFactory); 
        } 
    } 
    return(new GUIDrawDibFactory); 
} 

int main(int argc, char * argv[]) { 
    GUIFactory *        guiFactory = GUIFactory::GetInstance(argv[1]); 

    /* actual gui calls for instance, button, window, etc. 
    Line * line = guiFactory->CreateLine(10, 10, 246, 246); 
    line->draw(); 

    return(0); 
} 
as you can see in the main function you don't see any reference to what rendering platform you use. There are only the primitive you need.

perfect encapsulation...

hope this helps

Posted: Mon Aug 06, 2007 10:32 am
by Candy
MessiahAndrw wrote:Are classes are just really structures except with methods?
You can add methods to a struct too. A class is a struct. The only difference is that a struct by default has public members (methods and variables) and a class by default has private members.
Could I have:

private-header.h:

Code: Select all

class MyClass
{
public:
  // constructor and methods here
private:
  int someMember;
  IDirect3DDevice9 *superHiddenMember;
  int someOtherMember
};
and in:

public-header.h:

Code: Select all

class MyClass
{
public:
  // constructor and methods here
private:
  int someMember;
  int someOtherMember
};
So I don't need to define IDirect3DDevice9. Do I even need to include the private methods in my public header at all?
If your private methods are a part of the class interface, then yes, you do. There is a common method for hiding such implementation details, called the pImpl idiom, as well as the more generic interface definition, which requires you to define the interface and then implement it.

Posted: Tue Aug 07, 2007 2:20 am
by AndrewAPrice
I have an idea:

This is the public header:

Code: Select all

class IMyClass
{
public:
  MyClass();
  virtual void MyFunction();
};
And here's the private header:

Code: Select all

class MyClass_DX9 : public IMyClass
{
private:
  int someMember;
  IDirect3DDevice9 *superHiddenMember;
  int someOtherMember;
};
Is this what you mean about pImpl?

Edit: I found this: http://en.wikipedia.org/wiki/Opaque_pointer#C.2B.2B

Posted: Wed Aug 08, 2007 10:20 am
by Candy

Code: Select all

class Concrete : public Abstract {
    class Impl;
    Impl *pImpl;
public:
    // Abstract functions that only forward

};

Code: Select all

#include <AwkwardImplementationHeader.h>
class Concrete::Impl {
    // the actual local functions, local storage, etc
};

Concrete::func() { return pImpl->func(); }

Posted: Thu Aug 09, 2007 3:48 pm
by os64dev
aha bridge pattern \:D/

Posted: Sun Aug 12, 2007 7:12 am
by AndrewAPrice
Here's an example of what I've decided to work with:
This is from texture.h

Code: Select all

#ifndef _MGF_TEXTURE_H
#define _MGF_TEXTURE_H

#ifdef MGF_LIB
	#include <d3d9.h>
	#include <d3dx9.h>
#endif

namespace MGF
{
	struct TextureInternal;

	class Texture
	{
	public:
		Texture(const char *name, IDirect3DDevice9 *device);
		~Texture();
		void SetNext(Texture *next);
		Texture *GetNext();
		const char *GetName();
		TextureInternal *GetInternal();
	private:
		TextureInternal *m_internal;
	};

#ifdef MGF_LIB
	struct TextureInternal
	{
		Texture *m_next;
		char *m_name;
		IDirect3DTexture9 *m_texture;
	};
#endif
}
#endif
All .cpp inside files of my framework start with #define MGF_LIB to indicate it is a library source. That way, an end-program does not need to know how MGF::Texture works and can easily pass it around in its program and does not need the DirectX SDK installed. Library source files can still access the underlying IDirect3DTexture9* for rendering by using Texture.GetInternal()->m_texture.