Writing a program framework. Classes and stuff.

Programming, for all ages and all languages.
Post Reply
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Writing a program framework. Classes and stuff.

Post 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.
My OS is Perception.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re: Writing a program framework. Classes and stuff.

Post 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.
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Re: Writing a program framework. Classes and stuff.

Post 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?
My OS is Perception.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re: Writing a program framework. Classes and stuff.

Post 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?
User avatar
Kevin McGuire
Member
Member
Posts: 843
Joined: Tue Nov 09, 2004 12:00 am
Location: United States
Contact:

Post 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.
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post 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?
My OS is Perception.
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post 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
Author of COBOS
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post 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.
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post 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
My OS is Perception.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Post 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(); }
User avatar
os64dev
Member
Member
Posts: 553
Joined: Sat Jan 27, 2007 3:21 pm
Location: Best, Netherlands

Post by os64dev »

aha bridge pattern \:D/
Author of COBOS
User avatar
AndrewAPrice
Member
Member
Posts: 2299
Joined: Mon Jun 05, 2006 11:00 pm
Location: USA (and Australia)

Post 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.
My OS is Perception.
Post Reply