Criticise my D3D code please

Started by
18 comments, last by Aardvajk 17 years, 8 months ago
Quote:Original post by Anonymous Poster
[...]

it is also too neat.

you have really got to let your hair down a bit and let the vectors start flying


I agree with this. But it does depend from person to person on how much you want to balance cool code versus cool output.

An immediate improvement is to call CVertex something else. Perhaps CDefaultVertex. Also, the float x,y,z should be encapsulated within a vector of three floats, D3DXVECTOR3 or your own, possibly named "position". I say this because you'll eventually have more than one vertex type and possibly multiple positions in the programmable pipeline. But, I guess it's perfectly fine for an engine of this size.
Advertisement
I would make some methods inline like the Begin or End for instance.
@ dx elliot - thanks for the advice. I doubt this wrapper will ever be used much beyond experimentation but I will bear in mind your points about the vertex structure in the future.

Quote:Original post by dx elliot
But it does depend from person to person on how much you want to balance cool code versus cool output.


Bit confused by this. Where is the tradeoff, exactly?
Quote:Original post by tj963
On the matter of friends from the C++ FAQ. Friends can break encapsulation (and frequently do) but not necessarily.

tj963


Ugh, their example is terrible - if you break a class into two parts, and then you make them friends so that they can get at each others' guts, then you haven't really broken the class into two parts. I would only deem that argument as acceptable during an early refactoring phase - something to be corrected in a subsequent pass. Otherwise, bad programmer - no cookie.

They do have a valid point w.r.t. friend being not worse then adding accessors for everything, but that's like saying that it's not much worse to be poked in the left eye versus the right eye.
Quote:Original post by JasonBlochowiak
They do have a valid point w.r.t. friend being not worse then adding accessors for everything, but that's like saying that it's not much worse to be poked in the left eye versus the right eye.


Adding accessors to everything would allow anyone to access the private members, whereas only a friend could access otherwise non-accessible private members. One thing to watch out for, though, and this is an argument for friending being a hack, is that friends aren't inherited.

One roundabout, ugly way of doing a safer friend-like thing is to declare those members as protected, then have a subclass that has private accessor functions to those protected members, and friend someone to that class, who can then access that data only through the subclass's private accessors, which no one else can use. But, then again, you could accomplish the same thing by creating that sublass class privately inside what would have been the friend, and making the accessors public. I dunno, I'm just musing here, and don't know if any of this would work, or be worth doing.
Well, you are all absolutely right and I agree that from a strict theoretical programming point of view my wrapper has broken some fundamental rules. Were this designed to be used by other people, or as library code, I would certainly consider a serious refactoring to address these issues.

Can I assume though, as per my original question, that the actual use of the D3D stuff is as efficient as is possible, since no-one has posted any criticism of that?

Sorry to keep badgering about this but I only started out with D3D a couple of weeks ago and I'm keen to get the early stages right.

Thanks.
Quote:Original post by EasilyConfused
Can I assume though, as per my original question, that the actual use of the D3D stuff is as efficient as is possible, since no-one has posted any criticism of that?
I assumed somebody else would pick this up, but I guess not.

From a D3D standpoint, your wrapper negates many benefits of using VBs, with nothing in return. You force a specific vertex format, which is completely inappropriate for any but the most trivial apps. You force a function call to write each and every quad, which is a performance nightmare. You appear to provide no facilties whatsoever for handling device lost. And why are all VBs forced to be dynamic? The acquire and release functions should be part of the class constructors and destructors. There's no support for only modifying sections of a VB (particularly useful in combination with no-overwrite locks).

That's just at a quick glance. I don't see any of this code providing real benefits, just removing flexibility in an attempt at simplicity. If you want to make solid base classes, you're going to need to start over from design phase.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
Thanks promit. I really wanted someone to address this kind of thing.

To deal with these points in random order, in the hopes you or someone else can suggest some better ideas:

It was suggested to me elsewhere on gamedev that dynamic vertex buffers were the best solution for a 2D sprite library, since I would be regenerating all the vertex data every frame, which is also why I've used D3DLOCK_DISCARD. If I was mis-advised, I'd appreciate that advice being corrected.

I didn't consider that a function call for writing each quad would produce any kind of noticable overhead, since the calls are not locking and unlocking the buffer, but just writing to an already locked buffer. Could you explain the potential overhead here, which I assume from your post must be more than the normal overhead involved in a function call, since that is pretty negligable on a modern computer, and also perhaps suggest an alternative that would avoid the code that uses this wrapper having to manipulate the vertex data directly?

I am aware that this code is not checking for device lost, or even testing that the hardware supports the formats and capabilities I am using and had planned to add this later, but I appreciate you pointing this out.

I did not put the acquire and release code into constructors and destructors since this would force these actions to occur at the beginning and end of the scope of the device object, buffer object and so on, which was not what I wanted, but I suppose I could re-wrap all the objects into another class in the main engine that would place these actions in the appropriate place. I don't really see how this presents any performance issues though.

I have not attempted to add support for modifying sections of buffers since the strategy for drawing with a 2D sprite based game as I see it is generally to recreate ALL the vertex information each frame. I wanted to create an interface that presented the facility for a similar approach to using something like DirectDraw but would be glad to hear suggestions for how this could be improved, bearing in mind that there would be very little or no quads that would remain fixed from frame to frame.

This isn't meant to be a flexible, 3D-capable wrapper. The idea is to present an interface specifically for drawing 2D sprites with the flexibility of DirectDraw but with as little D3D performance overhead as possible within that flexibility.

With this in mind, could you advise on the disadvantage of having a specific vertex format, since I don't want to be able to draw anything but textured quads with this wrapper.

Any suggestions for improvement would be gratefully recieved.

Thanks. Paul
Alright, so let's see how would be best to set this up, keeping your actual usage in mind.

First, CVertexBuffer -- not a good name. Doesn't really describe what this class does. (Also, ditch the capital C. It's pointless.) What we actually need is some kind of list of sprite objects. These sprites will all be combined into a buffer every frame and then rendered. For now, we'll keep it simple:
class Sprite{public:    int X, Y, Width, Height;};typedef std::vector<Sprite> SpriteList;typedef SpriteList::iterator SpriteIterator;

Now, we'll need some kinda object to keep a set of buffers cached.
struct Vertex{    float x, y, z;    D3DCOLOR diffuse;    float tu, tv;};class SpriteBuffer{private:    IDirect3DVertexBuffer9* m_Vb;    IDirect3DIndexBuffer9* m_Ib;    unsigned int m_SpriteCount;public:    SpriteBuffer( unsigned int maxSprites );    ~SpriteBuffer();    void Begin();    void End();    void Write( const SpriteList& spriteList );    void Clear();};

The exact functions you use may vary somewhat, and I leave the implementation up to you, but that should get the idea across.
SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.
That is a very good idea that I appreciate you taking the time to post. My thanks.

This topic is closed to new replies.

Advertisement