• entries
8
10
• views
7489

Re-inventing the wheel for six months and running....

## What's this? Another Entry!?

Well, I know I just updated yesterday, but I finished up the graphics class and the alpha mapping functionality ended up providing for some really neat affects, so I just thought I would share a screen with you all.

I didn't change any of the sprites, so all of the affects are done with alpha maps, even the little camouflage thing the fire dude has going on. The entire screen has a fog-like filter applied, which really adds to the atmosphere.

## Cleanup

So it's been a long time since I have made any updates, but I assure you this is not due to lack of progress on my part. In fact, I have finished both the asset and graphics management systems and have finally settled on my chosen method for propagating the objects about through the separate modules. I have also added a good deal of new functionality and established a framework that will allow me to implement even more (aka full alpha maps for each image, rather than a global alpha value per image).

Unfortunately, most of this progress has been behind-the-scenes stuff, so I don't really have any more to show for it than I did before - at least as far as pretty pictures go.

However, just to give you an idea of how vastly improved my code base is, here is a comparison of the asset instantiation and loading code (for only a single object), both before and after the asset system:

BEFORE:
// Here is just the initialization and loading for the Character object //CImage* CharUp1    = NULL;CImage* CharUp2    = NULL;CImage* CharUp3    = NULL;CImage* CharUp4    = NULL;CImage* CharDown1  = NULL;CImage* CharDown2  = NULL;CImage* CharDown3  = NULL;CImage* CharDown4  = NULL;CImage* CharLeft1  = NULL;CImage* CharLeft2  = NULL;CImage* CharLeft3  = NULL;CImage* CharLeft4  = NULL;CImage* CharRight1 = NULL;CImage* CharRight2 = NULL;CImage* CharRight3 = NULL;CImage* CharRight4 = NULL;CSprite* CUpSprite = NULL;CSprite* CDnSprite = NULL;CSprite* CLfSprite = NULL;CSprite* CRiSprite = NULL;CObject* ChrObj    = NULL;CharUp1    = new CBitmap( "./Data/Images/Character/CharUp1.bmp" );CharUp2    = new CBitmap( "./Data/Images/Character/CharUp2.bmp" );CharUp3    = new CBitmap( "./Data/Images/Character/CharUp3.bmp" );CharUp4    = new CBitmap( "./Data/Images/Character/CharUp4.bmp" );CharDown1  = new CBitmap( "./Data/Images/Character/CharDown1.bmp" );CharDown2  = new CBitmap( "./Data/Images/Character/CharDown2.bmp" );CharDown3  = new CBitmap( "./Data/Images/Character/CharDown3.bmp" );CharDown4  = new CBitmap( "./Data/Images/Character/CharDown4.bmp" );CharLeft1  = new CBitmap( "./Data/Images/Character/CharLeft1.bmp" );CharLeft2  = new CBitmap( "./Data/Images/Character/CharLeft2.bmp" );CharLeft3  = new CBitmap( "./Data/Images/Character/CharLeft3.bmp" );CharLeft4  = new CBitmap( "./Data/Images/Character/CharLeft4.bmp" );CharRight1 = new CBitmap( "./Data/Images/Character/CharRight1.bmp" );CharRight2 = new CBitmap( "./Data/Images/Character/CharRight2.bmp" );CharRight3 = new CBitmap( "./Data/Images/Character/CharRight3.bmp" );CharRight4 = new CBitmap( "./Data/Images/Character/CharRight4.bmp" );CUpSprite = new CSprite( 0.175f );CUpSprite->AddFrame( CharUp1 );CUpSprite->AddFrame( CharUp2 );CUpSprite->AddFrame( CharUp3 );CUpSprite->AddFrame( CharUp4 );CDnSprite = new CSprite( 0.175f );CDnSprite->AddFrame( CharDown1 );CDnSprite->AddFrame( CharDown2 );CDnSprite->AddFrame( CharDown3 );CDnSprite->AddFrame( CharDown4 );CLfSprite = new CSprite( 0.175f );CLfSprite->AddFrame( CharLeft1 );CLfSprite->AddFrame( CharLeft2 );CLfSprite->AddFrame( CharLeft3 );CLfSprite->AddFrame( CharLeft4 );CRiSprite = new CSprite( 0.175f );CRiSprite->AddFrame( CharRight1 );CRiSprite->AddFrame( CharRight2 );CRiSprite->AddFrame( CharRight3 );CRiSprite->AddFrame( CharRight4 );ChrObj = new CObject( 400, 300, 0 );ChrObj->AddSprite( CUpSprite, "CHAR_UP" );ChrObj->AddSprite( CDnSprite, "CHAR_DOWN" );ChrObj->AddSprite( CLfSprite, "CHAR_LEFT" );ChrObj->AddSprite( CRiSprite, "CHAR_RIGHT" );ChrObj->AddSprite( CDnSprite, "CHAR_DEFAULT", 0 );// And here is the cleanup in the WndProc, which is the reason all// of this fragmentation was necessary in the first place.if( CharUp1    ) delete CharUp1;if( CharUp2    ) delete CharUp2;if( CharUp3    ) delete CharUp3;if( CharUp4    ) delete CharUp4;if( CharDown1  ) delete CharDown1;if( CharDown2  ) delete CharDown2;if( CharDown3  ) delete CharDown3;if( CharDown4  ) delete CharDown4;if( CharLeft1  ) delete CharLeft1;if( CharLeft2  ) delete CharLeft2;if( CharLeft3  ) delete CharLeft3;if( CharLeft4  ) delete CharLeft4;if( CharRight1 ) delete CharRight1;if( CharRight2 ) delete CharRight2;if( CharRight3 ) delete CharRight3;if( CharRight4 ) delete CharRight4;if( CUpSprite  ) delete CUpSprite;if( CDnSprite  ) delete CDnSprite;if( CLfSprite  ) delete CLfSprite;if( CRiSprite  ) delete CRiSprite;if( ChrObj     ) delete ChrObj;

AFTER:
AssetSystem.SelectObject ( "CHARACTER" );	AssetSystem.SetPosition ( 368.0f, 268.0f, 20.0f );	 AssetSystem.SelectGroup  ( "IDLE" );	 AssetSystem.SetFrameDelay( 0.2f );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharDown1.bmp", 200 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharDown2.bmp", 175 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharDown3.bmp", 150 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharDown4.bmp", 175 );	 AssetSystem.SelectGroup  ( "UP" );	  AssetSystem.SetFrameDelay( 0.2f );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharUp1.bmp", 200 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharUp2.bmp", 175 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharUp3.bmp", 150 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharUp4.bmp", 175 );     AssetSystem.SelectGroup  ( "DOWN" );	 AssetSystem.SetFrameDelay( 0.2f );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharDown1.bmp", 200 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharDown2.bmp", 175 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharDown3.bmp", 150 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharDown4.bmp", 175 );	  AssetSystem.SelectGroup  ( "LEFT" );	 AssetSystem.SetFrameDelay( 0.2f );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharLeft1.bmp", 200 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharLeft2.bmp", 175 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharLeft3.bmp", 150 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharLeft4.bmp", 175 );	  AssetSystem.SelectGroup  ( "RIGHT" );	 AssetSystem.SetFrameDelay( 0.2f );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharRight1.bmp", 200 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharRight2.bmp", 175 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharRight3.bmp", 150 );	  AssetSystem.AddImage     ( "./Data/Images/Character/CharRight4.bmp", 175 );

As you can see, the second sample, though still somewhat lengthy, is MUCH better than the first. Keep in mind that this is only for a single object - there's no telling how many objects will need to be loaded for a real scene. The initial approach would be impossible to use for anything larger than four or five objects.

On a similar note, creating the graphics system forced me to rearrange some functions, and the decrease in function calls actually improved my framerate by a small margin. A nice bonus indeed.

So the engine is far more manageable now, and I am putting the finishing touches on the graphics system as we speak. Or as I type, rather.

Next up are the physics and input systems.

## Frameworking. Sort of.

I finally managed to get my asset management system working to a reasonable degree. I'm using a CVectorMap to store all of the objects that will be used in-game, so all that is required for other structures to access the objects is to pass around a reference to that structure.

All items/characters/npc's/etc. will inherit from the CObject class (think the Java Object class), so the CAssetSystem is mainly responsible for keeping each object organized and up-to-date.

The entire project is looking much less bleak than it was during my last post. I am now working on the graphics and physics systems, which will really help to tie everything together and give me a full picture of whether or not my current design is going to work. As with all the other aspects of this engine, I'm just relying on trial and error to figure out what works and what doesn't.

So yeah, not much to see here - but I'm really relieved to finally have a semi-viable solution to my engine's design. Christmas has really distracted me from working on the project, but hopefully I'll be able to get more done in the coming weeks. Merry Christmas to all of you!

## A little housekeeping and a plea for advice.

Admittedly, this update comes much later than I would have liked. I have been working as much as possible on an asset management system for the Essentia Engine, but I've had a lot of distractions of late. Both the semester and my rotation at Cisco are coming to an end, so I've had a lot of tying up loose ends and final preparations to keep me busy.

Nonetheless, I did manage to get a little bit of work done on Essentia, though I don't have much to show for it. To begin with, I have created a CVectorMap class, which uses two std::vectors to create a templatized map container which performs an insertion sort as you add items to the container, and uses a binary search to access said items in a timely fashion. The identifier is a char* array, which lets you do cool things like order frames in a sprite animation simply by naming them something like "FRAME1", "FRAME2", etc. This also allows me to implement a global asset management system, which keeps track of all the assets via their string identifiers.

The asset system takes care of all of the memory management for all CObject, CSprite, and CImage objects. This is much simpler than what I'm currently doing - my placeholder Main.cpp is garbage. But we'll worry about that later.

The asset system is still highly in development and refinement, so I am loath to say anything about it because I guarantee that it will be completely rewritten several times before I'm happy with it. So for now, let's just say its a work-in-progress.

And that's about it. Now that I have enough of the engine finished that it is actually beginning to have some form, I realize that it needs a massive organizational makeover. First engine...lots of mistakes. But hey, at least I'm learning, right?

Hopefully, I'll get a lot of development time starting this weekend and extending throughout Christmas break. My little brothers are on my case, asking me when I'm going to "hurry up and finish the engine so [they] can make their game." So I'm under a little bit of pressure. :)

For now, I am focusing on organization - which is work enough in and of itself. I feel that I need to create some kind of outline for this beast, or else I'll get lost in the code and lose sight of the big picture. I'm hoping that sectioning everything off into dedicated modules will help things a bit. I'm thinking of creating an asset module, graphics module, physics module, application module, and eventually a sound module.

Who knows, I might just ought to diagram the whole thing out. If anyone has any suggestions, by all means please instruct me - I'll definitely take whatever advice I can get.

## Finally finished.

Today, at approximately 4:15PM, I passed the ONT and concurrently completed the full CCNP. I have just returned from a good night's celebration, and I am now going to sleep for the next 48 hours.

Updates are forthcoming, in case anyone was worried - but sleep comes first. Goodnight.

## Animation

I finally managed to get my sprite animations working to my liking. The system is fairly robust, allowing you to insert and remove frames at any point in the buffer, and specify a unique string identifier that allows you to seek to any specific frame. You can also alter the speed of the animation by specifying a delay between each frame update, which is calculated based on the global timer.

The executable (in RAR format) can be found here.

It has become painfully clear to me, now that I'm having to load in multiple frames for each animation, that I need to implement some sort of asset management. That and collision detection are next on my list, so expect to see some updates in the next week or so.

## Busy, busy, busy...or am I?

So between work and studying, I haven't had much time to work on my project, now officially dubbed "Essentia." I did manage to sit down for a couple of hours yesterday and get the sprite animations up and running. I'm still polishing up the code, but the base implementation is complete at this point.

In the past I had used sprite sheets, but after some consideration it seems as though using individual images would be simpler to implement, as well as provide faster execution times. The speed increase would be due to fewer calculations and a much smaller buffer index; namely a buffer of image pointers versus multiple buffers containing the RGB values of the images themselves. Based on previous tests to pinpoint speed bottlenecks in the engine, the sole act of indexing into a large buffer seems to consume a lot of processing power. Nonetheless, even if the speed gain were negligible, the ease of implementation, as opposed to calculating the indices for the individual frames, causes the multiple image approach to be much more appealing.

So that's what I'm going to go with.

I was originally using a self-written dynamic array class (appropriately named CDynamicArray) that I had used in the past for less involved applications. Although resizing arrays is considered a costly operation, none of the additions were being made during run time, so I decided to use the structure for my sprite animation buffers. However, upon successful compilation, I immediately began to receive heap corruption errors. Initially, I had no idea what could be going wrong. Based on the debug call stack, it looked as though all of my images were being deleted prematurely. I spent a good half hour stepping through the program before I located the code causing the problem, and I'm still not sure what the source of the issue was, unless my understanding of the c++ delete[] operator is incorrect. I researched the topic, and all the documentation I found seemed to agree with my original understanding, but perhaps I am missing something - I will detail the problem below and hopefully someone here can explain.

So here goes...

My sprite class contains a CDynamicArray of pointers to objects of type CImage, which is my image class. Think of it as an array of pointers. Inside the CDynamicArray class, I had functions to take care of all the resizing and copying of elements that would have to take place each time an element was added or removed. So the InsertItem function code would look something like this:
template void CDynamicArray::InsertItem( TYPE tItem ){    // ... Error Checking Omitted ... //    TYPE* pTempList[] = new TYPE[m_iSize];    for( int i = 0; i < m_iSize; i++ )        pTempList = m_pItemList;    delete[] m_pItemList;    m_iSize++;    // ... Resize m_pItemList ... //    // ... Copy Old Items Into m_pItemList ... //    // ... Cleanup ... //}

I don't have the source anymore (as I am no longer using this method), but the omitted code is irrelevant. The focus here is on the delete[] m_pItemList line in the middle. m_pItemList is an array of CImage pointers that has already been correctly initialized.

So here is where I'm confused: my understanding of the delete[] keyword is that it deletes the memory allocated to store elements, but does not delete the memory allocated to the elements themselves. For full, correct memory management, you actually have to loop through the array, prior to deleting the array itself, and delete all of the array's elements first. So in my example, the array itself should have been deleted, but the pointers should remain intact, and all of the documentation material that I found seemed to agree. If anyone knows the source of the discrepancy, by all means feel free to enlighten me, but I'm stumped at this point.

Oh well. All of this was probably for the best, because it didn't take me long to realize that I could save myself a lot of grief (and probably speed things up in the process) by simply using a std::vector in place of my CDynamicArray class. All hail the STL!

And that, my friends, is where my rambling ends. I replaced all of my previous custom structures with std::vectors, and my code now compiles and executes perfectly, and actually looks a lot cleaner as well. So if there is anything to be learned from this, it is that the standard template library is a standard for a reason, and is not to be trifled with.

I submit.

In other news, I managed to pass the ISCW on Thursday and am now only one exam away from the full CCNP and an end to the socially-decrepit, sleep-deprived life that I have subjected myself to for the last three months. This also means that within the next two weeks or so, I will able to fully devote my time to Essentia, and you fine folks will no longer be forced to listen to my error-induced rambling but will be provided quality, tangible content that should put to rest any concerns as to the validity of the claim that I am "working on it."

Until next time.

## Hello World!

Hello GDNet! Obviously, this is my first journal entry, so I'll take a few lines and introduce myself.

I am 19 and a sophomore at NC State University, double majoring in computer science and computer engineering. I am currently three weeks away from completing a six-month intership at Cisco Systems, where I work in the Cisco TAC (Technical Assistance Center) labs. As you may have already guessed, my interests include, but are not limited to, computer graphics and networking, specifically network security.

And that's quite enough about me.

I am currently working on a (perhaps frivolous) project involving writing a software implementation of some of the more common games-relevant aspects of the GDI+ graphics library.

I think it's referred to as a library...?

Anyhow, the project spawned from an earlier project in which I attempted to build a sprite-based game engine, first using DirectX 9 sprite functions and then, after realizing that I really had no idea what was going on with DirectX, with GDI+.

I quickly realized that GDI+ was somewhat less than adequate for the implementation that I had in my head (involving full alpha blending, dynamic scaling of images, etc.), and I found myself in a bit of a rut. I didn't really understand DirectX as much as I would like, but GDI+ couldn't do what I wanted. So what was I to do?

At that point, I'm sure many of you would just have sucked it up and delved into DirectX, but I didn't (and still don't) care to attempt to tackle wrapping my mind around a 3D API until I have a solid understanding of the more basic 2D concepts.

And so, my project began.

Six months later, and after many periods of little to no actual development, I have a basic graphics engine working, at relatively acceptable frame rates (the definition of which, I have learned, is somewhat subjective) - a steady 30 FPS. Nonetheless, I am pleased with the project thus far, and am planning to expand it into a full-blown engine, with several tools (i.e. image loading and sound libraries, etc.) that I can utilize in any further engines I may develop later on.

While I am new to large projects, I'm not so new as to be unaware of the fact that my goals are lofty, and that many projects such as this have been started and never finished, for various reasons. I've learned enough from the small amount that I have actually accomplished, however, that regardless of how far I actually get, what I do manage to accomplish will be well worth the experience and knowledge gained.

The first image simply shows some of my programmer art (yay!) while the second demonstrates the ability to alpha blend literally any and every image. The alpha blend is a true "divide by 255" blend, so it is slow, though the "bitwise shift 8" trick only improves the performance by a frame or two on most computers. Go figure.

The entire project is being written in pure C++, the only exception being a three-line "Present()" function in the CBackbuffer class which grabs the window handle and makes a call to std::BitBlt() in order to display the backbuffer's contents to the screen.

I'm sure there are other technical details that I should cover, but at this point I think I have far exceeded the acceptable "initial post" size limit, so I will leave you with a link to the executable and hope that I have somehow managed to pique someone's interest.

Controls for the demo are as follows:

Arrow Keys :: Movement
Shift :: Toggle Alpha Blending/Speed Mode
F12 :: Toggle FPS Counter
F11 :: Toggle FPS Limit

Until next time, I bid you farewell.