I had a day off from work on Monday.
I’m so rested right now that I feel tired because of it.
Once in a while, especially after a
longer post, I’ll come back and revisit it. I’ll do this to clarify some
points, list some alternative techniques, do some natural follow ups or
anything else that does not introduce a new concept.
This is what I’ll be doing right now
for lesson number one. If you look over most DXUT (and even straight DirectX)
examples out there, they are a huge pile of spaghetti code, with a bunch of
global variables and a few functions. I would like to add a little more OOP
styled structure to it. You may also notice that a large amount of code remains
completely unchanged from sample to sample. I would like to both create a
minimal framework that allows the reuse of these snippets and to put it into
action to make my samples leaner (and meaner, but not like that macro).
But keep in mind that what I am
trying to do is not a wrapper. I do not want to introduce another layer on top
of what is already a layer on top of DirectX. I just want and an OOP structure
to DXUT styled application and add a little code reuse. What I’ll be using will
serve exactly this purpose and nothing more, so don’t expect good and flexible
design, qualities that would recommend this approach for anything more than
small tutorial applications or anything that hides the DXUT approach an turns
it into a high(er) level abstract CG framework.
Today I am only offering a preview of
this approach. I’ll take the example from my last post and show how it looks
after the changes. I’ll give the same treatment to lesson 2, so I’ll explain a
second official tutorial as is and in the follow up show how it can be done in
a more OOP style. Only in lesson 3 will I formally introduce the classes that
are involved and post full source code for them. Until then, here is a preview
for the DXUTApp class:
It is a very simple class that
mirrors the callback approach from DXUT and has some very basic functionality
implemented for each callback. Go back to lesson number one to see what these
callbacks are used for if you need to. Their name has been cleaned up a little
and I hope you’ll have no problems matching things up. Let me list the default
functionality of these methods:
- IsDeviceAcceptable will simply return true, so all devices are accepted.
- ModifyDeviceSettings returns true, so the application will accept any settings.
- OnCreateDevice will return S_OK, thus not creating or modifying any resources. The same goes for the 3 other resource creation/destruction functions.
- OnResetDevice will return S_OK.
- OnLostDevice will return S_OK.
- OnDestroyDevice will return S_OK.
- OnFrameMove does nothing.
- OnMessage returns 0 and does not process any message.
- OnFrameRender will clear the back buffer with the color black and clear the Z-buffer.
These member functions
take the same parameters and have the same return type as their non member
counterparts, except for the void pointer used for custom data. If you need
custom data just place it into your class that inherits from the DXUTApp class. In practice I have not encounter
a single example yet where this would not be enough and you needed to have that
extra parameter.
The class also has a
Register method. You need to call this once and should be one of the first
things you do in the main method.
Using this class you
could simply instantiate as a local variable in your main function, call
register and then proceed with the normal DXUT setup functions. You don’t need
to use any of the DXUTSetCallbackXXX methods
and using them after the Register call will actually break the functionality of
the class. Doing this will net you with a black window that should run OK on
pretty much any computer known to man (if it has DirectX 9 support).
But we are not going to do this. We
are going to take it one step further and inherit from this class and override some
functions so we get an example that has exactly the same functionality as the “EmptyProject”
SDK sample:
We inherit from the DXUTApp class and
only override the methods we need to. In practice this means that in real
examples we’ll override every single method. On the other hand, after 2-3
lessons we’ll isolate some code that is repeated and stick it into a class and
start inheriting from that class to reduce code repetition. Let’s take a look
at the implementation of these methods:
The code for IsDeviceAcceptable is
100% identical to the one from the original sample. In fact I just copied it
over, this is why I did not rename the parameters to a slightly more reasonable
and uniform scheme. I did this intentionally to show that you can take existing
code and fit it into my scheme. This is vital I think for beginners. Once you
get the hang of DXUT you’ll have not problem switching things around as much as
you please. Anyway, the function does the same alpha blending support test to
exclude some devices from running this application. Soon we’ll exclude
everything that does not support pixel shader 2.0 and once we target pixel
shader 3.0 the pixel shader 2.0 code paths will be treated as fallback.
The second function we override is
the rendering one. Since the default implementation from my class fills the
frame with black and our original sample did so with blue, we need to override it.
As explained earlier, this is not meant to be a full framework that you would
use in let’s say the implementation of a serious project, like a commercial game.
Under such circumstances you would probably add support for background colors
and even a full stack of modular post processing effects. Here we just copy the
code and change the color:
The final piece of the puzzle is the
main function:
The function pretty
much looks the same, but instead of registering a bunch of callbacks we just
register our instance of the class. Even though this is not meant to be a
wrapper, the base DXUTApp class will get some minor improvements as time goes
by. As an example, for me personally the use of “DXUTMainLoop();” is quite jarring. Since
we are doing things OOP and already have a local variable called “app”,
invoking the main loop should look something like “app.MainLoop();”.
But this will be sufficient for our first preview of the OOP approach.
I need to save something for later.
As I reminder, for people who skipper the first post from this series
because it was too long, let me reiterate the purpose of the series: I want to
share a few useful shaders that took me quite a while to piece together from
dozens of sources on the Internet. Finding good and easy to understand shader
information out there is quite the scavenger hunt.
Meanwhile I have decided to add about 3 more lessons on the subject
of terrain rendering as a bonus. While creating the procedural terrain renderer
I tried a few techniques that are reasonable and can be useful but did not fit
my particular needs. I want to preserve them too.
So that’s the basic idea: if I spent hours trying to piece together a
shader that in the end I did not get to use, I’ll post it here (but only if I
can do it in a comprehensive way) before it gets lost somewhere on my hard
drives and I forget how they actually work.
Could you possibly get some sort of code coloring plugin to use and actually insert the code rather than taking screenshots? As it's not text, it's a bit hard to see on my setup. Also if I wanted to copy/paste and play with it.
ReplyDeleteIf you click on the picture it should display it at full size and it should be readable.
DeleteMost of the code is from the DirectX SDK.
Other code will be attached somehow. Just need to find a way to make sure that the attachments are persistent. I hate it when I find a 5 year old web page where the code links/pictures are no longer available.