PDA

View Full Version : multiple code paths



ScottManDeath
06-12-2002, 11:30 AM
Hi

currently I'm beginning to write the base for a game. As you can imagine while writing the base you should pay attention what your target hardware will be.
My target will be GF3/GF4 because I will try to play a little bit with NV_pointsprites and pixel/vertex shaders. The problem I have at this time is how to arrange my code (C++) so that I can implement a fallback code path for non GF3/hardware? There the minimal hardware plattform would be a TNT2 class card with EXT_texture_env_combine...

I can imagine 2 approaches:
At app start check what codepath it should use.
a) when for example rendering some bump mapped object do a if/then/else to determine which extension should be used,when no fitting extension, then skip bumpmapping

b) make for example the particle system a base class and derive one for each codepath and while creating a new particle system choose what implemenataion to use

I would like to know what you think, currently I' tending towards b) because its OOP but how do you do solve such problems.

The 'engine' is not meant to be a omnipotent engine that will be used as a long term base, instead it is thought to learn about doing more than just rendering cubes and spheres. My fears are that I do much 'overkill' by making it as reusable as possible.
It would be nice to get some hints or information how you do it
Bye
ScottManDeath

Mezz
06-12-2002, 12:38 PM
It's possible to check things on the fly with simple if/else statements, but if you've got quite a few codepaths I could see that getting unwieldly.
In cases where you can define the behaviour at application startup it's better to do that - whether it's via function pointers or derived classes, at least you have less runtime check overhead (you get a bit on the pointer dereference, but I'm not sure it'd be too noticable).

For classes that are created dynamically it can be a bit tougher because you still have the path-decision code to handle as the class is instantiated. I guess it wouldn't be too bad to do a switch or some if/elses in this instance. You may also consider abstracting the creation into another class, something that had several functions within it like:





BaseSys *CreateGF4System();
BaseSys *CreateGF1System();
BaseSys *CreateR7500System();
// and so on


It may also have one function pointer that is assigned at startup to the appropriate creation function depending on the hardware. This way your code can always call the same instantiation function knowing that it will point to the correct one in the class for the hardware. Of course, this may not fit in with the design of your particle system.

I don't want to ramble anymore, sorry if the idea seems a bit trashy but I'm a bit dreary right now.

Perhaps you can pick something off it and find a good solution. http://www.opengl.org/discussion_boards/ubb/smile.gif

Have fun,

-Mezz

MikeC
06-12-2002, 01:29 PM
Yeah, this is just crying out for some variant on the Factory pattern. Same basic idea as Mezz describes, just organized a little differently.

Create a ParticleSystem base class with a virtual render() method, which uses basic unextended GL. Create a Factory base class with a virtual createParticleSystem() method returning a ParticleSystem pointer (raw or smart), which creates and returns a new ParticleSystem. That's your basic implementation.

Now, derive a WhizzyParticleSystem from ParticleSystem, and override render() to use the NV point sprite extension. Derive a WhizzyFactory from factory, and override createParticleSystem() to create and return a new WhizzyParticleSystem. That's your GF3/GF4 implementation.

At app startup you determine what you're running on, and you create either a Factory or a WhizzyFactory; in either case, you store a polymorphic pointer or reference to the object somewhere accessible. (Probably as a singleton.) Now, when you want to create and render the best particle system you can, you don't have to write any if/switch code at all. Just do:




// assume pf is a pointer to our
// well-known factory singleton

ParticleSystem* p=pf->createParticleSystem();
p->render();


And virtual dispatch does it all for you.

Obviously this is a simplified example; there are any number of variations. Your Factory will almost certainly do more than just create psystems. But you get the idea.

HTH
Mike


[This message has been edited by MikeC (edited 06-12-2002).]

rIO
06-13-2002, 01:37 AM
Another way could be to use a C like solution, I've implemented it once for a complete different task, but it worked (it was dongle check for enabling/disabling application features).

I just created classes contanining function pointers insthead of real functions, in the app/class init code I checked which of the features where available and then just filled the function pointer with the needed data.

This way implementing NEW extensions and using the classes was quite easy and useable.

Pseudocode Sample :

Init()
{
if bumpextension_available()
this->BumpFunction = HardwareBumpFunction;
else
this->BumpFunction = SoftwareBumpFunction;
}

then in the code i can use

Shape->BumpFunction();

whithout taking care of extensions...

and MAINLY without falling in endless if/else code....

just my 2 cents...


rIO.sK

ScottManDeath
06-13-2002, 07:03 AM
Hi

thank you for your hints,they look interesting.I have following idea to do that correct instantiating of classes by itself
Consider following code:

// forward declaration
class GF4ParticleSystem;
class TNT2particleSystem;

class ParticleSystem:
{
public:
ParticlesSystem()
{// some global variable
if(use_gf4)
{
delete this;
this= new GF4ParticleSystem();
}
else if (use_TNT2)
{
delete this;
this= new TNT2ParticleSystem();
}
else
{
//construct
}

}

virtual void Render(); // render using gl1.1
virtual void Simulate();
};
class TNT2ParticleSystem : public ParticleSystem
{
public:
virtual void Render(); // multitexture ...
};

class GF4ParticleSystem : public ParticleSystem
{
public:
virtual void Render(); // pointsprites
};


With doing so everytime I create a ParticleSystem,in theory there will be the correct one created. When for example I will support ATI extensions, I just would make a new ATIParticleSystem class and change the ParticleSystem constructor. What do you think, will that result in runtime overhead ?

Bye
ScottManDeath

Kilam Malik
06-13-2002, 07:14 AM
I don't think, that

this = new Class();

will compile...


I'd suppose a singleton factory:




ParticleFactory *ParticleFactory::fac = 0;

class ParticleFactory()
{
public:
ParticleSystem *GetParticleSystem()
{
if (GF3)
return ParticleSystemGF3();
if (GF4)
return ParticleSystemGF4();
}

static ParticleFactory *GetFactory()
{
if (!fac)
fac = new ParticleFactory();

return fac;
}

protected:
static ParticleFactory *fac;
};


ParticleSystem()
{
virtual void Render() = 0;
}

ParticleSystemGF3()
{
virtual void Render()
{ ; }
}

ParticleSystemGF4()
{
virtual void Render()
{ ; }
}


void main()
{
ParticleSystem *myHardwareParticleSystem = ParticleFactory::GetFactory()->GetParticleSystem();
};


Kilam.