• Categories


  • HDX (DirectX) Framework and Demo Minigame

    No Comments


    I have been working on a project to familiarize myself with the DirectX API (originally learned OpenGL). To that end I have thrown together the minigame Spacechase. The scenario is that you are piloting a dropship that is trying to catch up to a faster and much larger hostile ship. This other ship is synthesizing and transporting asteroids out behind it in an attempt to slow you down. As a result of this process some orbs of plasma also end up in the mix, which, when picked up by the player, grant a substantial speed increase. The player wins by catching up with the other ship. While, on the other hand, the player loses when they have hit 3 asteroids.


    The player’s control over their movement is confined to the plane perpendicular to the direction they is flying, denoted by the large light-green circle in this diagram:



    The player is also unable to get too far away from the origin of the plane, meaning they cannot simply fly away from where the asteroids are, they must weave in and out of them to survive.





    The language I am using is C++. I am heavily utilizing some of the new features in C++ 11; most notably being <functional>.


    C++ 11:

    I make very heavy use of lambdas; mainly for callbacks for things like GUI events, messages, and function registry. I also use them as sort of my own abridged rendition of graphics APIs’ programmable pipeline. For example, my shader classes (discussed below) render function takes a lambda as an input and calls various clerical code before and after the passed in code. The code that is passed in being actual render calls.


    I make use of the new unordered_map as a fast and easy to use hash table for GUI elements, entities, lights, and pretty much everything else. I have created two classes template<class DATA,class KEY> class BaseManagerKey and template<class DATA> class BaseManagerID, which combine the random access speed of the new unordered_map with the sequential access speed of an old vector. The only difference between the two variants is that the key type of the latter is hardset to an int and new IDs are automatically generated. These classes also make use of the pattern described above, of passing in a worker lambda, allowing lower level work to be done without exposing too much functionality, via a function named doIterate(). The only drawbacks of these managers is that they take up an extra DWORD per item,  and their insertion and deletion times are significantly longer than only a straight vector or unordered_map.



    All graphics are done using DirectX9. The main sections of DX9 I am utilizing are the ID3DXSprite interface for GUI elements and text, and ID3DXMesh for the actual models. I also make use of the programmable pipeline (via ID3DXEffect) with my custom pixel and vertex shaders, in which I have implemented Phong Lighting for directional, point, and spot lights.



    As mentioned above, I have implemented Phong Lighting, via custom vertex and pixel shaders. The vertex shader transforms the vertex into homogeneous clip space as normal, except it passes the word-space normal and position to the pixel shader as well. This normal and position are both automatically interpolated to equal those of the rasterized pixel the pixel shader is working on. The pixel shader then performs the calculations for the lighting of every pixel individually. The lighting value for ambient, diffuse, and specular are calculated and combined with the both the material and texture’s (if applicable) color to determine the final color.

    Here is a snippet of code from the pixel shader for calculating the point light:



    Light demo clips:

    All of the lights have their ambient and diffuse set to white, while each have a different specular color;

    Directional light:


    Point Light:


    Spot Light:


    On the C++ side of the lighting system I have implemented a Phong Lighting shader class (HDXShader_PhongLighting). This class is responsible for containing and managing the ID3DXEffect instance as well as all of the separate HDXLight’s. To deal with the separate lights it implements the factory pattern. In its update function all of the lights’ data (position, colors, direction, etc.) is aggregated and passed to the shader running on the GPU.



    The basic camera is implemented as a 3d position vector and a quaternion denoting its orientation, along with some snazzy functions to make modifying the quaternion easier, including: rotateYaw/Pitch/Roll, setLookAt, and setLookDirection. There is also a free-look fps-style camera derived from this base class that encapsulates the handling of keyboard input to move the camera and mouse input to change the view direction. This is used in the lighting type demo. The camera used in the actual minigame LERP’s its position towards a position above the back of the player’s ship. This is to reinforce the feeling of motion and speed when the player’s ship changes velocities.



    Demo clip:


    Class Diagram:


    My GUI system is hierarchical, in that every element is the child of another element and any change applied to one element affects all of the ones below it. A new GUI menu starts out with a special element type fittingly called HDXUIMenu. It is special as it is the only type of element that does not require a parent. Other elements can then be added to the menu via a template factory system. Effects can also be applied to any element via a similar factory procedure as child elements. Effects are responsible for doing most of the visual work of a GUI element. Most elements have an effect that draws a sprite (HDXUIElementEffect_TextureDraw), as well as one that draws text (HDXUIElementEffect_TextDraw). Effects are also the mechanism by which transitions are implemented. Special Transition Effects (like HDXUIElementEffect_Transition_LERP) can be initialized to respond to messages such the menu entering and exiting.


    Here is an example of how to define a button:



    Here is an example of how a basic positional lerp transition is defined:



    As it is template quite strongly and uses lambdas for getting and setting the value it is very robust and can work on any variable that is desired.



    Sound is handled by FMOD. I wrapped FMOD’s initialization as well as some functions for loading and playing various types of audio into a small class for convenience. This class’ main method is the overloaded HDXSoundManager::playSoundChannelGroup() function, which provides an easy way of playing sounds in the various channels (music, gui, and fx), as well as having it loop or play only once. I also wrote a small music management system that allows for crossfades between two tracks, accomplished by using a simple lerp algorithm.



    To test for collisions between the objects in the game I used OBB bounding volumes, via a separating axis test.



    Comment RSS

    No Responses to “HDX (DirectX) Framework and Demo Minigame”

    Leave a Reply

  • Recent Posts

home login