Site Sections

Tuesday, December 18, 2007

VB Crazyness

So I found out something interesting today while working in VB. Even though Debug and Release modes are no different since VB does not generate .obj intermediate files, there is an issue that sometimes the complier will not be able to generate good errors with a simple build command.

Today I had some funky errors stating that I had syntax errors where none existed, and error underlining on the line above where it was saying the error was located. Really strange stuff. I finally thought to do a rebuild (since there are no intermediate files - or so I thought, didn't think it would help) Apparently, this fixed my problem. Very strange....

If VB Modes Debug and Release are different, someone please feel free to comment on this and correct me as I would like to know the difference. C++ is obvious as they generate two separate assemblies that are very different due to the debugging information.

Saturday, December 1, 2007

Updates

I have been working on my 2D engine of late, and I have been making some updates to the managers I have written tutorials on. I have already updated the GUI manager with regards to an issue I ran into with sprite tinting. I will also be updating it later to include the optimizations that I made last month using reference passing for some of the larger objects.

As far as the development of the engine, I have been making great progress on how I am going to handle the states of the game. This is greatly important for RPG style games where dialog changes, controls change, and GUI Components rendering changes based on the current location and activity in the game. I have written a state manager that takes much of this into account and I believe that it is quite an elegant solution. I will be posting a tutorial on this here later.

Check out the changes to the GUI Manager tutorials if you have used this code anywhere. It will save you a lot of headache when trying to tint sprites and you can't figure out why (I think I spent a good hour looking at it wondering why it wasn't working).

Saturday, November 17, 2007

Texture/Model Manager Tutorial

Finally it has arrived, my tutorials on Texture/Model Managers that I had promised two weeks ago. It took me some time to get a chance to add it to my blog, I have been playing with Photoshop a bit this past week and just haven't had the motivation to work on my engine. I was adding a Height map that I found on RandomChaos 3D's site

Well, it was really frustrating me, so I am taking a break from the 3D stuff for a few weeks, going to start on a 2D engine so I can learn some more .Net stuff in building a level editor/event editor for a traditional RPG that I have in mind, (thus the photoshop work).
Regardless, Texture managers (and perhaps model managers) are still useful tools for 2D and I will be porting them over to my new engine. So I still feel that they are an important topic to cover here on this blog.

Texture Manager

So managers are a useful tool for storing information that can be resource intensive (such as textures and models) that have the potential of being generated more than once when they do not need to be. For instance, say we have 6 types of wall textures for our level, 2 types of ceiling textures, and 4 types of floor textures. Yet each of these textures will be used many times by every room in our level, whether they are simply tiled, or if they are going to be blended in our pixel shader that we use for our walls. Regardless, we still do not need to load these static textures multiple times into memory, not to mention, if we ever want to change what texture we have on our walls, or whatever we are texturing, we do not want to have to load new textures in the middle of our runtime loop.

Thus the texture manager comes into play. Here I have use the same principles that the Hazy Mind engine uses for shaders. A simple approach that uses a map to map texture objects to named indexes. Below is the code for my Texture2DManager:



using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using System.Collections;

namespace HMEngine3D.TextureManager
{
/**
* Texture2DManager
* Handles loading static textures for static textured objects
*/
public class Texture2DManager
{
// The table of textures
private static Hashtable mTextures = new Hashtable();
// The table of new texture asset locations
private static Hashtable mTextureAssets = new Hashtable();

/**
* AddTexture
* Adds a new Texture to the table of managed textures
*
* Parameters:
* aNewTextureAsset - The location of the new texture to add.
* aTextureLabel - a Name to reference the new texture by.
*/
public static void AddTexture(string aNewTextureAsset, string aTextureLabel)
{
// check for valid parameters
if (aTextureLabel.CompareTo("") != 0 &&
aNewTextureAsset.CompareTo("") != 0 &&
mTextureAssets.Contains(aTextureLabel) == false)
{
// add the new texture to the table
mTextureAssets.Add(aTextureLabel, aNewTextureAsset);
}
}

/**
* GetTexture
* Returns the Texture of the given name if it exists in the table.
*
* Parameters:
* aTextureLabel - The name of the shader to retrieve.
*
* Return Values:
* aOut - The texture in the table of the given name,
* null is returned if it does not exist.
*/
public static void GetTexture(ref string aTextureLabel, out Texture2D aOut)
{
// check to see if the label is valid
if (aTextureLabel != null && mTextures.ContainsKey(aTextureLabel))
{
// if so return the texture
aOut = mTextures[aTextureLabel] as Texture2D;
}
else
{
// the Texture is invalid, returning null
aOut = null;
}
}

/**
* LoadGraphicsContent
* Loads all the Textures in the table into memory from file.
*
* Parameters:
* aDevice - The Graphics Device to load to.
* aLoader - The Content Manager to use for loading the textures.
*/
public static void LoadGraphicsContent(GraphicsDevice aDevice,
ContentManager aLoader)
{
// loop through the textures in the table
foreach (string lTextureLabel in mTextureAssets.Keys)
{
// load the shader into memory from file
Texture2D lTexture = null;
lTexture = aLoader.Load(mTextureAssets[lTextureLabel] as string) as Texture2D;
if (lTexture != null)
{
if (mTextures.ContainsKey(lTextureLabel) == false)
{
mTextures.Add(lTextureLabel, lTexture);
}
}
}
}

/**
* EmptyTextureManager
* Empties out the texture manager of all currently loaded Textures.
*/
public static void EmptyTextureManager()
{
mTextureAssets.Clear();
mTextures.Clear();
}
}
}


You can see here that I used some of the optimizations that I discussed in my last post, the out reference passing as well as some in (ref) reference passing of variables in parameter lists. This isn't a serious optimization but it doesn't hurt. So here we can see that we can use these basic functions to add and retrieve texture assets from this manager. We want to add the textures that we want to load prior to the call that we will make to the LoadGraphicsContent function. This will allow the texture manager to load all of the texture assets all at once.

Since this is a static class, we will use this much in the same way that we already use our Shader manager. To keep this short and to the point, the other places that need code added to them are

  1. Any object that currently loads a texture, needs to be modified to simply keep a reference to their desired texture and add some code to retrieve their desired texture after the content has been loaded. Do not put code to search the manager in your draw loop, this is in-efficient and will slow down your engine!! Only search the manager when you need to switch texture assets, this is why the engine returns a reference to the object.
  2. In our main game class, we need to add some code to load our desired textures, for instance if you have a map parser, keep a list of used textures in a section of your map file. Then when you parse this, (I recommend that it be one of the first things you do) have it build your list of textures/labels prior to referencing them from your objects.
  3. We will also need to add in our engine a call to the LoadGraphicsContent function for our texture manager, this should be near the top of our Engine's LoadGraphicsContent function, this will allow us to use the other objects in our game to use their LoadGraphicsContent functions to retrieve their texture assets from the TextureManager
Thats it for the texture manager. Now we have a simple storage class for all the large texture assets in our game. Give it a try!

Static Model Manager

I'm not going to get in depth in the code for the Static Model Manager since it is the same as the Texture2DManager, just for different object types. Suffice to say, the reason it is for Static Models only is that, if you plan on having any sort of animation of your models, you will need to keep different references to them. It will give you trouble if you modify your model every time you switch objects. Use this for world objects that do not move (thus the term static).

If you have any problems porting the Texture2DManager over to a StaticModelManager, feel free to drop me a line and I will try and give you a hand.

Keep On Coding!

Friday, October 26, 2007

Optimizations - Simple and Effective

I was working on my engine the other night, trying to get my new managers to work with a simple map parser that I am working on (I will be putting up the tutorials on the managers in a few days), and I noticed that I was starting to get some major slow down while rendering models, especially when I got any more than say 20 objects on the screen. Lag city I tell ya! It was really depressing.

Time to optimize...

C#, like many languages (especially C/C++) give you the option to pass values by reference. This means that instead of "passing by value" meaning copying the contents of a variable into another stack variable created for the called functions parameters, we instead simply create a reference (or pointer) to the location in memory where the passed variable is stored. This works great for larger objects as we do not want to have to create a separate copy of every object we want to pass as a parameter, especially if we are passing the object down a couple of calls.

This was my first optimization that I noticed I could perform. Now C# has two forms of pass by reference when dealing with function calls:
  1. Simply to pass a reference to a function by identifying it with the "ref" keyword, this must be placed in the function definition and the function call.
  2. Passing return variables by reference, this requires the use of the "out" keyword before the return variable INSIDE of the parameter list. We do not return these variables as normal, instead we can assign them a value and it acts as if we are assigning the value to the variable from the calling function scope. This is much faster than using standard returns when using them for assignment operations, also it allows for multiple return values. I have modified my managers to use this form of returning when doing searches for objects contained within.
This sped up the Hazy Mind engine quite a bit on its own. I did notice a major improvement when it came to the return speed on the shader manager. This got me thinking as to why the shader manager was giving me such poor performance. I started looking around and I noticed that in all the draw loops for objects, the Hazy Mind engine uses the shader manager to request the shader to draw with every time through the draw loop.

Hmmmm, I think to myself, why are we doing this? I am assuming it was in case someone wanted to change the shader of an object in the middle of the game? Well why not then move this expensive search cost to the setShader function and store a "reference" to these objects locally. Small memory hit, vast performance increase. We amortize the cost of searching to constant (actually practically nothing since we shouldn't need to change shaders on specific objects very often) and tada! almost instant improvement in speed, I can have many more objects on the screen with no lag. I have my render framerate fixed and it doesn't jump at all. I can imagine that my unfixed frame rate would now be through the roof.

So key things to remember:
  1. Use pass by ref, especially in functions that you are not going to change the state of the parameter objects. It really isn't all that much of a benefit on basic data types as their size is pretty much the same as the size of the reference.
  2. Use out return parameters for managers that return bulky objects such as models.
  3. keep search times low by not putting them in draw loops (this is very very important!)
Hope this helps!

Wednesday, October 17, 2007

Engine work again!

Well, it looks like I have found some time to do some more work on the engine. Last night I started writing a few more managers to handle static textures and models for my next goal of building a level editor. I noticed that the Hazy mind engine loads each texture and model at the time that the the load content function is called. It also loads the same texture multiple times if the developer creates multiple copies of the same object. I think that I can streamline this assuming that I know what textures and models are going to be loaded like a library.

This would make sense in a standard game as I can develop a map file that contains a list of all the assets that are going to be used in a level. These can be loaded into a manager and used like a lookup table when they are required.

When I get this functionality fully working I will post a tutorial here. Check back soon!

Tuesday, October 9, 2007

Car Troubles...

Man, sometimes I just feel like quitting driving. If only I could, I think I would. Not only would it save me the money in gas, but also from dealing with leaking radiators, bad service at Precision Auto, and all around car problems.

So here is my story:

My car was overheating, it would take radiator fluid while it was cool and it wouldn't leak. Turns out that when I ran it, it would still overheat no matter how much coolant I put in it. Also when I turned off the car, it would leak like a siv from the front corner of my driver side. I looked under the hood, and it didn't seem like any hose was leaking that I could see, so off to Precision Auto to get it checked out for radiator leaks. They look at it, never call me back with an estimate, figure out apparently that a clamp on a hose has come loose. I call them a few hours later right before they close and they say this to me and tell me that they have already fixed it, without my consent. I should have told them that, that was it and I wasn't going to pay them since they never called me back. Well, I was just happy to have my car fixed I paid it, whatever. Turns out it was 48 dollars in labor just to fix a clamp and run a pressure test. They tell me it turned out ok, radiator holds pressure, cost me a buck for a new clamp.

I drive it home, no overheating, so I'm happy right? Drive it to work and I didn't even pay attention to whether or not it was fixed, it seemed to be running fine. I get out of work just as Precision is about to close and notice that my heat is rising again... now I'm pissed right? They said it should be fixed. I get it home and look, sure enough, still leaking. I pull out my cell and give Precision a call back, and they say "Oh it might be your thermostat sticking, I can get you in on Thursday".

This is ridiculous, I shouldn't have to pay for service again, and this time I tell you I won't. Parts maybe but definitely not labor, it's their fault, they told me it was fixed. Moral of the story, walk or ride a bike, it's healthier, better for the environment, and a whole lot cheaper. If only I could, too bad I live in the U.P. of Michigan...

... needless to say, I have been dealing with either trying to find a new car to purchase or fix this one, not so much working on my game... Very sad :( hoping to get back to it soon, right after I beat Resident Evil for GC.

Monday, October 1, 2007

Woot for scanners

Yay! I finally got my new scanner on Friday, unfortunately I have had absolutely no time to play with it yet. I got the software installed just before I had to take off for the weekend to Marquette. Well, hopefully I will get the chance to play with it tonight and get some pictures that I have drawn up here.

As far as the scanner is concerned though, it is a Canoscan Lide 25 from Canon, it is a nice little scanner, smaller than a 17 inch widescreen laptop and fits in my laptop bag. The best part though is that it doesn't have a power supply, it is powered solely through the USB cable. This is nice for those crazy occasions where you are on the road and your life depends on scanning an image into your laptop on the go. (I don't know when that would be but just in case...) You can check it out here - (NewEgg) if you would like to get one yourself, they are cheap, only 60 bucks! Woot!

Friday, September 28, 2007

Resident Evil Revisited

Man, sometimes I love digging up a classic and playing through the experience one more time, especially when it is one of my favorite games of all times. In this case, it is two of my favorite games of all times, only because it was remade and so well done. Thats right, Resident Evil for the GameCube. I started playing it again the other night (I haven't seen the new movie yet and had watched the first two in preparation for tonights viewing). I wanted to show my girlfriend the intro to the GameCube version because she has never seen a Resident Evil game before. She thought it was good graphics for the system (which I would have to agree for its time) and that the overall feel of the environments were genuinely creepy.

I haven't played the remake all the way through, when I first got it I had been playing Super Smash Bros. and Zelda Windwaker like crazy and didn't really have time to play through a game that I had beat for the playstation when I was like 12. Yea it was pretty and supposedly it had additional content, whatever right? Playing through it again I can just not believe how much they improved on the classic. It is so much spookier than the original, yet all of the great original content is there in some form or the other.

For those of you out there that can't stand playing games that are more than a week old (and I know you exist - I use to be one of you) go back and play this game again, it is well worth your trouble in a time when we are all still waiting for spore...

Tuesday, September 25, 2007

GUI Manager Tutorial Pt. 2

So today we are going to talk about how to extend the abstract class of the GUIComponent that I showed you last time.

Remember, there are three important functions that need to be extended. These are the LoadGUIComponents, UpdateComponent, and Draw

Lets first discuss the type of component that we are going to make. We will be starting off with something simple that doesn't update to keep this tutorial hopefully short. Lets start with some simple GUI prototyping (placing test objects on the screen to get a feel for how the GUI will look). This way, we can spend less time trying to re-shuffle GUI elements around the screen later when we realize that our idea doesn't look good or fit and we have already spent a lot of time developing animation sequences/functionality/etc...

Lets start with a simple health bar, I whipped this image up really fast, it is in a .png format so the corners are transparent. This will be transparent in the game because if we look back at our GUIComponent class where we perform the draw loop, we can see that we have set up the SpriteBatch.Begin() function with the parameter SpriteBlendMode.AlphaBlend:



Not so exciting I know, but it took like 5 minutes, maybe I'll replace it later with something fancy. In the mean time, lets look at how to put this fine piece of artwork on the screen.

Lets add this image to the content directory of our game under a folder called textures for now. It can be moved later if you do not like it, or if you have some special hierarchy set up for each component in your GUI.

Here is our extended class of the GUIComponent, lets call it TestHUD:

using HMEngine3D.HMPostProcessors;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework;

namespace HMDemo.Content.TestObjects
{
/**
* TestHud
* Test Hud object for testing gui components on the HUD.
* It is an implementation of the GUIComponent Abstract class.
* It contains no interaction or animation.
*/
public class TestHud : GUIComponent
{

private string mAsset; // the name of the texture file to use
private Texture2D mTexture; // the texture to use.

/**
* Constructor
*
* Parameters:
* aAsset - The prototype image to draw to the screen.
* aPosition - The X,Y position to draw the object.
* aEffect - The Shader to draw the object with.
*/
public TestHud(string aAsset, Vector2 aPosition, string aEffect)
: base(aPosition, aEffect)
{
mAsset = aAsset;
}

/**
* LoadGUIComponents
* LoadGUIComponents is an overwritten method of the abstract class
* GUIComponent. It must be implemented by this extending class to
* load component specific GUI element assets.
*
* Parameters:
* aDevice - The GraphicsDevice load the graphics to.
* aLoader - The ContentManager to load with.
*/
protected override void LoadGUIComponents(GraphicsDevice aDevice,
ContentManager aLoader)
{
// load the texture asset
mTexture = aLoader.Load(mAsset);
}

/**
* UpdateComponent
* UpdateComponent is an overwritten method of the abstract class
* GUIComponent. It must be implemented by this extending class to
* update the component specific GUI elements.
* It currently does nothing in this class as this is only for
* rapid prototype testing.
*
* Parameters:
* aElapsedTime - The elapsed time since the last update.
*/
public override void UpdateComponent(GameTime aElapsedTime)
{
// do nothing yet
}

/**
* Draw
* Draw is an overwritten method of the abstract class
* GUIComponent. It must be implemented by this extending class to
* draw the component specific GUI elements.
*/
protected override void Draw()
{
mSpriteBatch.Draw(mTexture, mPosition, Color.White);
}
}
}


Ok, so now that we have a TestHud class, we can create one of these objects and pass our asset (the ugly health bar image) to the constructor as the asset, along with a position for it to display on the screen and an effect which should be a simple pixel shader (or more complex if you have some sort of special effect in mind).

We do this in our main initialization block of our code. In my case, I have a DemoGame class that has a Main method as the launch point of my application, this DemoGame contains an instance of my Engine code (or Game class as it is called by Microsoft). In the Main function, I set up all of my game objects, this is also where we are going to set up our HUD objects and register them with the manager.

Oh wait, we haven't put our GUIManager anywhere yet... that could be a problem when we go to register our HUD objects right? Well lets see where we want to put that. Since we so conveniently have a copy of our extended Game object near by, we should probably place it somewhere in there.

In your Game class, place a member variable at the top called:

protected GUIManager mGUIManager; // the gui manager

I know I am so original.

We then want to add some accessor methods to this class:

public GUIManager GUIManager
{
get
{
return mGUIManager;
}
}


And now we add some method calls in some key places to instantiate, initialize, update and draw:

In our constructor add:

mGUIManager = new GUIManager();

In our LoadGraphicsContent method add:

// load GUI Manager registered objects content
mGUIManager.LoadGraphicsContent(mGraphics.GraphicsDevice, mContent);

In our Update method add:

// update all the GUI Controls
mGUIManager.Update(aGameTime);

Finally, in our Draw method, and this is important, AT THE VERY END add:

mGUIManager.DrawGUI(ref aDevice);

This will draw the HUD on top of what is drawn by the post processor. This will keep the HUD unaffected by what the Post Processor does no matter what type of shader is used.

Now all we have to do is create an instance of our TestHud object and place this in our Main function of the game, we also need to register it with the GUIManager like so:

// create GUI
TestHud lTestHUD = new TestHud(@"Content/Textures/guiconcept", Vector2.Zero, "GT");
mGame.GUIManager.RegisterGUIComponent(lTestHUD);


*Note here, the "GT" parameter is the name of a basic pixel shader that I have mapped to this name via the ShaderManager described in the Hazy Mind Tutorials. It is recalled by the DrawComponent function of our GUIComponent class.

This should give us the results shown below.


As we can see, our Health bar shows up as we had hoped. Now if we want to make new GUI components, we can simply build a library of easily extended GUIComponents that only require us to implement 3 functions and add two lines of code to our main class to see immediate results. I hope that this will save you time in not only implementing sweet GUI Components for your Indy games, but also speeds up rapid prototyping for you. Please feel free to either e-mail me or post comments with any questions or... well... comments that you may have.

Monday, September 24, 2007

GUI Manager Tutorial Pt. 1

Well... the time has come finally for me to start my tutorial series for the GUI Manager built off of the Hazy Mind engine. It is really important that you understand the structure of this architecture prior to reading this tutorial. What I will discuss should be helpful for other architectures and probably could easily be adapted to work with them. The concept is very OOP, yet knowing how the Hazy Mind post processor is constructed will save us a lot of time. Go Here to review these tutorials if you haven't yet.

To start lets take a quick review of the overall layout of the game loop:



This is a highly simplified version of the actual game loop but we can see from this that the Post Processor redirects the engine's rendering to an off screen image. This image is then post processed by re-drawing the image using a sprite batch and a pixel shader. This allows us to use shaders that can blur/invert colors/tint/shift or do whatever other operation on each pixel of the screen. We can also use this technique to draw 2D images on the screen over the regular scene (GUI Controls also known as a HUD - Heads Up Display)

So here is our modified Game Loop:



Notice here how we simply add an additional layer to our render stack. This one however will draw images that lay over the top of the post rendered scene. placing this here allows us to avoid modifying the GUI components when we want to post process the scene. Instead we will design our GUI Manager to register controls that can hold their own shader information so each component can have different effects.

Our GUIManager class:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Collections.ObjectModel;

namespace HMEngine3D.HMPostProcessors
{
#region Utility Classes
public class GUIComponentCollection : Collection { };
#endregion

/**
* GUIManager
* Handles all of the 2D GUI Components that are
* drawn to the screen during game play.
*/
public class GUIManager
{

// Collection of GUI Components
private GUIComponentCollection mGUIComponents;

// Spritebatch to render with
private SpriteBatch mSpriteBatch;

/**
* Constructor
*/
public GUIManager()
{
mGUIComponents = new GUIComponentCollection();
}

/**
* RegisterGUIComponent
* Registers the given component with this
* manager so it knows to draw it.
*
* Parameters:
* aGUIComponent - The GUI Component to register.
*/
public void RegisterGUIComponent(GUIComponent aGUIComponent)
{
mGUIComponents.Add(aGUIComponent);
}

/**
* LoadGraphicsContent
* Loads the Graphics content of each of the
* gui components registered with the manager.
*
* Parameters:
* aDevice - The device to load to.
* aLoader - The content manager to use for loading.
*/
public void LoadGraphicsContent(GraphicsDevice aDevice,
ContentManager aLoader)
{
mSpriteBatch = new SpriteBatch(aDevice);
foreach (GUIComponent lComponent in mGUIComponents)
{
lComponent.LoadGraphicsContent(aDevice, aLoader,
ref mSpriteBatch);
}
}

/**
* Update
* Updates all of the registered GUI Components
*
* Parameters:
* aGameTime - The elapsed time since the last update.
*/
public void Update(GameTime aGameTime)
{
foreach (GUIComponent lComponent in mGUIComponents)
{
lComponent.UpdateComponent(aGameTime);
}
}

/**
* DrawGUI
* Calls the draw function of each registered GUIComponent.
*
* Parameters:
* aDevice - The GraphicsDevice object to draw with.
*/
public void DrawGUI(ref GraphicsDevice aDevice)
{
foreach (GUIComponent lComponent in mGUIComponents)
{
lComponent.DrawComponent(ref aDevice);
}
}
}
}

The construction of this manager is fairly straight forward. It simply generates a container utility class that holds a group of GUIComponents which I will explain in a moment. Each registered component is added to the list using the RegisterGUIComponent function. During the loading/updating/drawing functions, we loop through this group and perform the appropriate function. Notice how we use the ref qualifier on the mSpriteBatch variable when loading. This keeps the amount of memory used to draw the objects to a minimum since each component will contain its own drawing loop, this object can be shared.

So how do we construct a GUIComponent? We need to make it abstract! This is important so that way we can extend its functionality by enforcing a set of functions that need to be implemented by extending children classes. This way the GUI Manager knows how to render all of the children no matter what their functionality.

Here is the GUIComponent abstract class:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using HMEngine3D.HMShaders;

namespace HMEngine3D.HMPostProcessors
{
/**
* GUIComponent
* Abstract definition of the GUI components that
* can be managed by the GUIManager
*/
public abstract class GUIComponent
{

protected Vector2 mPosition = new Vector2(0, 0);
protected string mEffect = "";
protected SpriteBatch mSpriteBatch;
protected RenderTarget2D mRenderTarget;


/**
* Constructor
*
* Parameters:
* aPosition - The position of the GUI Component on the screen in pixels.
* aEffect - The Shader Effect to use to draw the GUI Component.
*/
public GUIComponent(Vector2 aPosition, string aEffect)
(
mPosition = aPosition;
mEffect = aEffect;
}


/**
* LoadGraphicsContent
* Loads the Graphics content, and the sprite batch used in this
* component.
*
* Parameters:
* aDevice - The device to load to.
* aLoader - The content manager to use for loading.
* aSpriteBatch - The Sprite Batch object to draw with.
*/
public void LoadGraphicsContent(GraphicsDevice aDevice,
ContentManager aLoader,
ref SpriteBatch aSpriteBatch)
{
LoadGUIComponents(aDevice, aLoader);
mSpriteBatch = aSpriteBatch;
mRenderTarget = new RenderTarget2D(aDevice,
aDevice.Viewport.Width,
aDevice.Viewport.Height,
1,
aDevice.DisplayMode.Format);

ShaderManager.GetShader(ref mEffect, out mShader);
}

/**
* LoadGUIComponents
* Must be implemented by the extending class.
* Loads all the graphics content for this component.
*
* Parameters:
* aDevice - The device to load to.
* aLoader - The content manager to use for loading.
*/
protected abstract void LoadGUIComponents(GraphicsDevice aDevice,
ContentManager aLoader);

/**
* UpdateComponent
* Updates the component for the current state.
*
* Parameters:
* aElapsedTime - The time since the last update.
*/
public abstract void UpdateComponent(GameTime aElapsedTime);

/**
* SetPosition
* Sets the position of the GUI Component.
*
* Parameters:
* aPosition - The new position of the upper left corner of the
* GUI Component.
*/
public void SetPosition(Vector2 aPosition)
{
mPosition = aPosition;
}

/**
* getPosition
* Returns the current position of the GUI Component
*
* Return Values:
* Vector2 - The current position of the
* upper left corner of the component.
*/
public Vector2 GetPosition()
{
return mPosition;
}

/**
* DrawComponent
* Draws the component by setting up render loop and calling
* implemented Draw function
*
* Parameters:
* aDevice - The GraphicsDevice object to draw with
*/
public void DrawComponent(ref GraphicsDevice aDevice)
{

// hijack the render target to draw the component off screen
aDevice.SetRenderTarget(0, mRenderTarget);

// draw the component shader free
mSpriteBatch.Begin(SpriteBlendMode.AlphaBlend,
SpriteSortMode.Immediate,
SaveStateMode.SaveState);

Draw();
mSpriteBatch.End();

// resolve render target (normally done by framework but
// since we took over the draw we have to do it ourselves)
aDevice.ResolveRenderTarget(0);
aDevice.SetRenderTarget(0, null);

if (mEffect != "")
{
// set up the effect and sprites
HMShader lShader = HMShaderManager.GetShader(mEffect);
if (lShader != null)
{
Effect lEffect = lShader.Effect;
lEffect.Begin();
mSpriteBatch.Begin(SpriteBlendMode.AlphaBlend,
SpriteSortMode.Immediate,
SaveStateMode.SaveState);

// draw the sprites
foreach (EffectPass lPass in lEffect.CurrentTechnique.Passes)
{
lPass.Begin();
mSpriteBatch.Draw(mRenderTarget.GetTexture(),
new Vector2(0, 0), Color.White);
lPass.End();
}

mSpriteBatch.End();
lEffect.End();
}
}
}

/**
* Draw
* Must be implemented by extending classes.
* Defines how to draw this Component.
*
* Parameters:
* aSpriteBatch - The SpriteBatch object to draw with.
*/
protected abstract void Draw();
}
}


*Note: If we look in the DrawComponents function, we see a reference to the HMShaderManager class, this is part of the Hazy Mind engine and simply maps Shaders that we pre-load to given names. This saves on memory and loading time.

So as we can see here, there are 3 abstract functions:
  • LoadGUIComponents - used to load the specific assets for the component, is called by the loading function of the GUIManager.
  • UpdateComponent - used to update the component based on the elapsed time, called by the Update function of the GUIManager.
  • Draw - used to draw the component using the passed in Sprite Batch reference, called by the DrawComponents function of the GUIComponent class, this sets up the render loop for
this component and allows each component to contain its own shader effect.

* note I have recently updated this section to fix a problem with sprite tinting, I have instead used the method of rendering off screen the contents of the components prior to rendering the component using the defined shader associated with the component. This allows for the basic sprite batch shader to handle tinting of sprites.

In the next tutorial, I will show you how to extend this abstract class to make a GUI component object. I will also show you how to interlace this GUIManager with the Hazy Mind engine, or any other engine that uses a standard game loop.

Friday, September 21, 2007

OMG! Rant Warning... Visual Studios stupid bugs

HAHAHA! Sorry had to get that out of the way... So today at work, one of the guys I work with showed me the dumbest error I have ever seen. It has been an issue that we have been dealing with for a few weeks ever since we all go dual monitors. It turns out that if you want to change the build configuration in Visual Studios .net 2003 and your second monitor is to the left or above the primary monitor, the drop down windows in the configuration build manager do not work. Hmmm... very strange right? It seems it has a problem drawing the drop down boxes in negative virtual space, and of course, instead of windows adjusting your origin based on your most left monitor, they instead use a negative coordinate system for monitors in this configuration. If you move the dialog back on the primary monitor or to a monitor in the right/bottom relative position of the primary monitor, no issues.

Another issue I noticed today, in wincore.cpp, Microsoft has so lovingly used the Goto statement in about 7 places. This is so strange as the goto has really become a thing of the past - especially in C++... Someone should do a count to see how many goto statements are in MFC alone, that would be an interesting figure to ponder. Gives me more reason to love the fact that I do not work at Microsoft.

Leave it to Microsoft to lead the way in reverse innovations. Keep up the good work Mr. Gates!

Wednesday, September 19, 2007

Busy Busy Busy

AH...... It's been a few weeks since I posted the last post about BioShock. I beat it finally, when I got free time between work and life. Now that thats over (Note: I loved BioShock, but the ending was very disappointing) I actually might have some free time to work on the game again. I went to a lecture last night from Tom Wujec, he was discussing imagination and innovation. Very interesting stuff and very inspiring.

This leaves me with the promise I gave the last time about the GUI Manager tutorial. I will get it up here, I have just been un-motivated lately after getting off of work. I plan on having it up here sometime either this week or next so check back soon.

I have been drawing a lot more though. I recently bought a book by DragonArt on drawing fantasy creatures. This has been very helpful in teaching me some of the basic flaws in my drawing style. I have noticed an immediate improvement in my drawing ability, which in turn has caused me to be more inspired to draw more. When it comes out looking good you tend to get less frustrated. Another thing Tom Wujec mentioned was a quote about how Steve Jobs hires based not on programming/technical skills but based on the ability to communicate and the ability to draw/be creative. I would have to agree with this view, anyone can learn to program, it takes much more skill and motivation to learn how to create.

As far as my drawing... when I get my scanner that I just bought from New Egg, I will scan some of the decent stuff I have drawn lately and post it here. Feel free to tell me that it sucks, I don't mind. I am learning and criticism and feed back are all part of the flow of creativity and growth.

Wednesday, September 5, 2007

BioShock Review and how it has consumed my life

BioShock BioShock... oh how I love thee... Unfortunately you steal my soul and all of my free time that I could be spending coding. Oh well, I just graduated a few months ago, I don't think that I need to conquer the world in one year. I do on the other hand need to conquer BioShock which I have no doubt in my mind that it will be the game of the year. Hands down this game rocks where other FPS games have been left wanting. The storyline is amazing and the whole feel is creepy and dark. The architectural design of the levels are breathtaking, especially if you have a direct x 10 compatible card. FPS fans this one is a 10 star title all the way.

As far as my programming is concerned, I did take a break from the game today and did some more work on my GUI Component Manager for the Hazy Mind engine. I got it working and will be posting tutorials here soon (maybe even tonight if I get ambitious - although BioShock is sooooo tempting ;)

Friday, August 17, 2007

Tile Texture Shader

Blah... so I am packing to go down state tomorrow, and I am bummed because I missed the chance to get some Oyster Eggs in KOL with one of my characters. So to make myself feel better I thought I would write a little tutorial today.

What we are going to cover is how to add tiling attributes for a texture shader. I figured out how to do this a few weeks ago when I was playing around in my engine (it's really not all that hard). I was trying to build interior walls like they use in the Unreal engine but I couldn't figure out a good way of building the subtraction space model they use in their editor... well needless to say, Unreal also has the ability to dynamically set texture location and scaling in its editor. I of course think this is very important when you want to line up textures and build walls that are longer than your texture is wide. So lets begin:

Here I have a basic texture shader:


float4x4 WorldViewProject;
sampler TextureSampler;

struct VS_INPUT {
float4 Position : POSITION0;
float2 Texcoord : TEXCOORD0;
};

struct VS_OUTPUT {
float4 Position : POSITION0;
float2 Texcoord : TEXCOORD0;
};

VS_OUTPUT Transform(VS_INPUT Input) {
VS_OUTPUT Output;

Output.Position = mul(Input.Position, WorldViewProject);
Output.Texcoord = Input.Texcoord;

return Output;
}

struct PS_INPUT {
float2 Texcoord : TEXCOORD0;
};

float4 Texture(PS_INPUT Input) : COLOR0 {
return tex2D(TextureSampler, Input.Texcoord);
};

technique TransformTexture {
pass P0 {
VertexShader = compile vs_3_0 Transform();
PixelShader = compile ps_3_0 Texture();
}
}



The concept here is very simple, take in the world-view-projection matrix and the texture sampler, and map them to the vertex texture positions. Then in the pixel shader we simply sample our texture for the appropriate color value and output that color. I have purposefully neglected to add any lighting to this shader for simplicity sake.

Here is a quad that I created that uses the simple version:



So now we want to provide the ability to offset the texture position and to be able to scale the texture for tiling purposes. We will add the following attributes to the top of the shader file so they are accessible from our code:



float TextureScaleX;
float TextureScaleY;
float TextureOffsetX;
float TextureOffsetY;



These values are going to be used in factors. This will make the math really simple, you will just have to remember how the math is done and everything will work out really easy when trying to set up your image. Now we will change our Texture function to perform the scaling and the texture offset. It looks like this:



float4 Texture(PS_INPUT Input) : COLOR0 {

float2 ScaledTexcoord = Input.Texcoord;
ScaledTexcoord.x *= TextureScaleX;
ScaledTexcoord.y *= TextureScaleY;
ScaledTexcoord.x += TextureOffsetX;
ScaledTexcoord.y += TextureOffsetY;
return tex2D(TextureSampler, ScaledTexcoord);
};



And there we have it. Our shader now can accept scaling and offset factors, for example all we would have to do to tile a quads texture to 2x2 tiles, would be to set the shaders x, y scale factors to 2 and we would have 4 copies of the texture displayed on the quad. Say we wanted to shift a texture over by 50% so the textures started tiling at the center of the image in the upper left corner, all we have to do is set the TextureOffset x, y to .5 and we get the result shown below.

Tuesday, August 7, 2007

The Woes of C...

I really dislike C, not because it is complex or that I do not understand it. It's not even so much that it is a functional language over a OOP (Object Oriented Programming) language, although that is frustrating. I just hate the libraries that have been developed for it. I dunno... maybe I am just stuck using really obnoxious libraries (specifically National Instruments LabWindows). Utility functions should be intuitive and they should be flexible, C functions that I've had to work with (although I haven't used many different libraries) are just cumbersome, take too many variables and are just all around bulky.

My other beef with C is local variable initialization, I hate having to define loop variables at the top of my function instead of in the loop declaration. I just don't understand why they couldn't write the compiler to declare stack variables while parsing the entire function, even if they had to parse the function twice.

I miss working in C++ :(

Monday, August 6, 2007

KOL Downtime and an XNA Book Review

So its 11:30 pm again... I hate when KOL goes down. It makes me very sad. I wonder what they do every night that requires the server to go down. I wonder if it just takes too much server time to update everyone's adventures. Any who... I went bowling tonight so I didn't get a chance to work on my game today but I did read some of the new XNA Game Studio Creator's Guide by Stephen Cawood and Pat McGee.

Here is my opinion so far: I don't know how long ago they wrote the book but it seems like there are better ways to handle some of the stuff they are doing, I wonder if they wrote it after the refresh. Maybe it is just my pet peeve that they use underscores in method names or what but their coding style is so far atrocious. Also they use Quake II models for animations, I haven't gotten to that part of the book yet (I am on chapter 4 so far as I just got the book Saturday - Shaders WOOT!) I am hoping that the chapter on the Quake animations will give me some insight on how to make Maya animations work in XNA since I am using the .X exporter for my models. Also it seems like there might be some good info on some geometry and Quaternion I might be able to use for camera controls and better character/obstacle control. I did notice though that the collision detection section was lacking in any sort of complex vertex collision on meshes. :(

I'm crossing my fingers...

Ill write more of a formal review once I have finished the book. I am disappointed that I can already tell that this book is simply too basic for what I want to do with my engine. Oh well... at least it will make some interesting reading for a few days.

Languages... when you know too many

This morning I was working on my game since for some odd reason I woke up 2 hours before I had to work. The funny thing is that I have just started using C# at the same time I started using XNA. Of course I work in C, C++ and Visual Basic for work and Michigan Tech teaches Java as its primary course language (among some others for special classes, such as LISP, Prolog, Veralog, Matlab, Fortran, etc...). It has been really easy to pick up C# as it is almost syntactically the same as C++, mixed in with a few things from Java. Granted it has its own things unique to the new .Net platform such as the "Using" keyword for things other than import libraries, the ever interesting partial classes, and a few other things I'm not all that familiar with yet, such as attribute tags and the new Getter/Setter syntax (I'm old school, I like method names with get and set in them).

The point I was getting at though, was that this morning I was trying to extend a class for the items from the HMModel class that was developed from the Hazy Mind site and I kept trying to use the super() call to the parent constructor. I did an F1 search and it even came up as a keyword to call the parent class for constructor calling and method access. Well it didn't work and I kept getting exceptions. Seems the correct use is to call base() in the initialization list like C++... Thats where knowing too many languages can cause you problems.

Sunday, August 5, 2007

Quaternion

So today I was working on Indy Game and I was trying to get the slerping working (fun flybys - Check out the Hazy Mind site for more info) for the turning of the camera when going through doors. Anyways... Yea, Michigan Tech is not exactly the best school in the world for graphics. See, I didn't hear about Quaternions until just recently (actually until I read the Hazy Mind site myself). I've taken graphics courses and although they were not very good, they were all in OpenGL but not in the sense of learning OpenGL, but to instead learn the basics of rasterization, line/point theory, phong shading, and stuff like that... I mean we didn't even get into any model file formats, or level design or anything of real use when developing game engines.

Enough ranting... The reason I am writing this is because today when I was trying to get the slerping working I kept having this problem with my camera over-rotating. It would rotate to almost the place I wanted it but not quite right. It always seemed like it over shot its target axis that I thought I was defining in my Quaternion that I was passing as a target rotation to the Slerp function in my engine.

Here was my code:


HMCameraManager.ActiveCamera.Slerp(HMCameraManager.ActiveCamera.Rotation *
new Quaternion(0, 1, 0, 1), .45f, SlerpType.Revolve);


The idea here was that I was attempting to have the camera "Slerp" 90 degrees to re-adjust the camera for when a player went through a door. I am hoping that this gives the player a real chance to see that the world they are in is really in fact a 3D world even though they are restricted to a 2D plane of movement (except for the doors of course). Well it seems that I don't really understand Quaternions all that well... the X, Y, Z components are not the directly related to which axis to rotate to. Well, after about 4-5 hours of tinkering and a lot of trial and error, I fixed my problem, it really was quite simple and I hate that it took me so long.

Here was my fix - Don't laugh (ok, you can laugh a little):

HMCameraManager.ActiveCamera.Slerp(HMCameraManager.ActiveCamera.Rotation
* Quaternion.CreateFromAxisAngle(new Vector3(0, -1, 0),
MathHelper.ToRadians(90)), .45f, SlerpType.Revolve);

You can see here that my change involved a little more calculation to create a Quaternion that I know for a fact is a 90 degree rotation. Makes things a little simpler in my mind, even if it does look a little sloppier. If anyone else has a better suggestion, please feel free to let me know.

Saturday, August 4, 2007

Indy Game I

So for the past couple of weeks, I have started development of my first XNA title. Initial development has gone into constructing the basic implementation of an engine. Current features include an OctTree for object culling, Skybox, object rendering, shader support, post shader processing, 2D HUD GUI manager (there will be a tutorial up here later once I get this working %100), and the beginnings of an input manager for both keyboard and 360 controllers.

The concept is being worked out and revolves around the premise of an indy game developer who was sucked into his own game, it is incomplete and he must beat the game to get back out. My idea is to develop the game as a sudo-2D environment using 3D models fixed on a rail.

The largest problem I have had so far involves camera functionality. The basis of the engine spawns from the Hazy Mind engine site (thanks Michael Schuld for the starting point and very useful information) but the code is quickly becoming heavily modified as the hazy mind engine is not really structured well for large scale projects.

Further updates will be added here later as I start generating screen shots, and better engine code for level generation and collision detection. I am really happy with how much XNA does simplify things. I haven't worked with it enough yet to fully understand how it supports other things such as animations imported from Maya but I am hoping to get into that stuff very soon as I will need animations for my characters.

Check back soon for more updates...

The Kingdom

I love Kingdom of Loathing, everyone should play it. The concept is truly original and the technology is so simple I am surprised there is that much content. Its amazing what a simple design can produce with a tight feature set.

If you haven't played KOL yet, check it out here

Don't forget greasemonkey plugins for firefox and the KOL Wiki

New Blog

This new blog is for development information on game projects currently in development by myself. This is the first post to put something up until i get some more time to put more information on.