I have run into similar issues and have settled on a similiar setup. My setup is also not the most efficient (but it is more efficient than 'immediate mode' drawing where everything renders itself upon its Draw() hook). I have a vector for each type of object that I want to draw. I currently empty the vectors upon completion of the frame, although I could easily just leave it and save the speed.
My system uses a vector which is not the most efficient. The render system iterates through the vector and renders the object. I tried to use one huge vertex buffer but so far have come up with several issues in doing this that are not easily solved - such as which sets of vertices to translate, etc., etc. This all requires either a dynamic vertex buffer array which is a bit slower than a static or you must compile the vertex buffer on the fly..which again is not the fastest thing in the world.
Again, same with me, textures are handled by a global texture manager. I use OpenGL, and the 'actual' textures are stored within the class, and the texture manager just hands out IDs...this makes it so you cannot load the same texture into memory twice (so if you do try to do that, the texture manager just hands out the ID to the previous copy of the texture...upon finding a texture that does not exist, the texture manager hands out an 'error' texture, which currently says 'you suck at life').
Textures for objects are stored in a global vector (actually a global instance of a class that handles the vector) and are each given an ID. ID's are then all that is used for the texture throughout the system. The actual IDirect3DTexture9 interfaces exist only in the CTextureManager class, but the texture ID can be used any number of times.
Correct, verbatim from what you said. While it is not perfect, it is pretty efficient and seems similar (if not identical?) to bubba's approach. Everything is also MUCH more reusable, and I never ever have to worry about choreographing the graphics anymore...if I want something drawn, I just add it to the renderer...fire and forget baby. Note that my renderer has a different data type to hold the data for each object to be drawn, for example, here's a data container for an MS3D model:
BobMcGee, I like your approach. So you still call the Draw() method on the Knight class, but that Draw method simply tells your rendered "Draw me!" correct? A good approach.
I use the Position and Orientation (angle about X,Y and Z) vectors to build the transformation matrix. Here's the function I call when I want to add a MS3DModel to the renderer:
Note that I do this every frame, but if I changed my setup just a tad I wouldn't have to (rather, I would just add stuff to the renderer as needed, but instead of removing it every frame just flag it as visible or not and save the time it takes to call new and delete all the damn time).
void AddMS3DModelToRenderer(float PosX,float PosY,float PosZ,
float AngleX,float AngleY,float AngleZ,
MS3DModelRenderData *pData = new MS3DModelRenderData;
pData->Position.x = PosX;
pData->Position.y = PosY;
pData->Position.z = PosZ;
pData->Orientation.x = AngleX;
pData->Orientation.y = AngleY;
pData->Orientation.z = AngleZ;
pData->pModel = pModel;
The biggest problem is that whenever I want a new 'type' of thing to be drawn, I have to add the following to my renderer:
-A data structure to hold it to distinguish it from other types
-A std::vector<DataTypeAbove> to the renderer class
-A function to add the type to the renderer
-The actual implementation of the rendering algorithm
Perhaps some of that *could* be alleviated by using polymorphism and OOP, but what I have works and I lead a conservative lifestyle.