Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!

1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Member Since 19 Jun 2009
Offline Last Active Aug 07 2014 09:36 AM

Topics I've Started

Resource Pointer Design

12 July 2012 - 06:26 PM

Working with the D3D API involves handling API resources via pointers. The API user is responsible for disposing of those resources.

In the spirit of modern C++ style, this is a job for some sort of smart pointer. But unique_ptr isn't a great fit, for a couple of reasons.

The way resources are acquired
The D3D API produces resources via "out parameters", which would require explict temporary pointers to transport resource addesses to owning unique_ptrs:
resource_type * pResource;	// Temporary pointer.
D3D_Make_Resource(&pResource);  // D3D style of producing resources.
upResource.reset(pResource);	// unique_ptr's style of assigning.

The way resources are freed
D3D resources are released, not deleted. Not only would unique_ptr require a custom deleter type to free the resources, it would require a unique deleter type per resource type, because each resource class has its own member Release() method, rather than sharing a common non-member function, like delete():
unique_ptr<resource_type, resource_releaser<resource_type>> upResource;

These aren't exactly show stoppers, but they're enough to take a couple of minutes to see if I can't do a little better. So I threw together a resource pointer class along the lines of this:
template<typename T>
  class d3d_resource_ptr
	  d3d_resource_ptr() : pResource(nullptr) {}
	  ~d3d_resource_ptr() {Release();}

	  T & operator *  () const {return *pResource;}  // Dereferencing works
	  T * operator -> () const {return  pResource;}  // like a normal pointer.

	  d3d_resource_ptr		 (d3d_resource_ptr const &);  // Unique ownership.  No need
	  d3d_resource_ptr & operator =  (d3d_resource_ptr const &);  // for copying (or moving).

	  void Release() {if(pResource != nullptr){pResource->Release();} pResource = nullptr;}

	  T * pResource;

The question is how best to get and set the raw pointer. Which is the lesser evil?

We could use a reference operator and implicit pointer conversion:
  T * * operator & () {Release(); return &pResource;}  // Pointer to pointer, for reassignment.

  operator T * () const {return pResource;}  // Conversion to T pointer, for storage or passing.

Which provides about as much convenience as possible:
D3D_Make_Resource(&rpResource); // operator & passes a T * * so the API can assign through it.
D3D_Use_Resource(rpPesource);   // operator T * generates a T * so the API can use it.

The evil here is that the resource pointer interface is a little too clever. It's hiding the fact that taking a reference automatically releases any resource (in anticipation of assigning a new one). That's an accident waiting to happen. And I suspect that implicit pointer conversions are trouble makers as well.

Alternatively, we could use explicit functions:
  T * Get() const {return  pResource;}
  T * * Assign() {Release(); return &pResource;}

  d3d_resource_ptr * operator & ();  // Protect against errant references.

Which produces code like this:

I guess the thing that bugs me the most about this is that I can't think of a better name for Assign(). I don't think its intention is entirely clear. What is clear is that this approach is not as clean as the previous option, and adds noise to already noisy function calls which handle several resources at a time.

So which is the lesser of the two evils? Or is there another way which is even less evil?

Would this be better or worse? :
  void Release() {if(pResource != nullptr){pResource->Release();} pResource = nullptr;}  // Now public.
  T * * operator & () {assert(pResource == nullptr); return &pResource;}  // Require Release() rather than calling it.

Asset Format and Loading Schemes

29 April 2012 - 06:30 AM

Over the years I’ve been pretty happy with solutions I’ve seen to lots of engineering problems. But there are a couple of areas in video games that seem resistant to solutions which don’t leave you thinking there just has to be a cleaner, easier, less error-prone, lower maintenance approach.

Probably the longest lived offender has been asset formats and loading. I would like to know your favorite asset format and loading schemes. I’m not talking about packaging, compression, streaming, etc. I’m talking about the binary layout and structure of asset data, and how loaded data becomes useable by the run-time code.

How does your favorite approach work? What are its strong and weak points?

Value-Subtracted Anti-Features

07 November 2011 - 07:18 PM

Before I start my rant, I want to acknowledge that many people don’t agree with me, and (get this!) they’re not wrong.

For example, I think MMORPGs are boring and bereft of gameplay. If a lot of people didn’t disagree, developers wouldn’t bother making them, never mind making ungodly amounts of money from them. So kudos to them for finding a market for whatever it is they’re selling. ;^) The point is, it’s understood that you probably disagree. I’m just writing to see if there’s anyone who doesn’t.

I once played a real-time tactics game which had probably the most entertaining cut-scenes I can remember. The gameplay was alright, but the cut-scene following each scenario is what really made them worth playing. Unfortunately the design contained (what was, in my opinion) a fatal flaw.

The player was given various “units” (that is, groups of same-type combatants, such as archers, cavalry, etc.) for each scenario. If a given unit had any surviving members at the end of a battle, the player could replenish that unit and carry them on to the next scenario. Obviously this was intended as incentive and reward for performing well. It adds a bit of variety and fun to the game, right? Well...

What inevitably ends up happening is that you run up against a scenario that you fail to beat several times running. And you start to wonder if perhaps, you hadn’t lost that one mortar unit, several scenarios ago, you might be able to succeed here. You can’t know for sure, but it’s possible you’ve actually hit a dead end due to under-performing earlier in the game. Practically speaking, this feature is actually a brutal punishment for not performing perfectly.

Do you really want to go back and replay the last two difficult, grueling scenarios, until you’ve beaten them “better” than you already beat them, to see if you could then get through this one? Ultimately this incidental feature, which was just supposed to feel like it was adding rewarding depth to the game, ends up robbing you of incentive to continue playing it at all.

Thinking about it, I’ve realized that I have similar feelings about lots of other “incidental, value-added” features.

Oooh, I get to choose whether I want my character to be able to develop these sorts of spells, or those sorts. That would be fine for a short PvP strategy scenario, but I have to lock myself out of the vast majority of character abilities in a long single player campaign? When I can’t possibly have enough information to make a truly informed decision? That’s just cruel. Oh but it’s called “re-play value” right? Great. I have to completely start over to see whether or not I would have liked a different choice better. It would take a hundred re-starts to actually find out what choices I prefer? Not. Gunna. Happen.

And it seems like these sort of choices and "rewards" are bad news for designers too. When you’re putting together a scenario, do you have to take into account, “What if he hasn’t earned the super shield, or found the jump-jet boots, or opted for the ice-ball spell, or, or, or” How well tuned can your scenario really be when it has to work with every one of a million different possible character configurations?

Couldn’t you arrive at something much more fun and focused if the state of the character was actually known at design time? The player might still earn upgrades that are fun and interesting, add texture to the game-play, and feel rewarding. They just don't need to be faced with meaningless dichotomies, abandon to dead ends, left to regret uninformed decisions, or punished for not being victorious enough.

Specifically, I'm talking about features that are added as an addition to a basic game-play mechanic, like adding ability trees on top of a hack 'n slash, or unit rewards to a real-time tactics game. It seems to me like many of these features are created for the appearance of adding depth to game-play, under the mistaken assumption that at least they can’t hurt. But in practice, they really do.