Saturday 31 October 2009

Something grey and scratchy

Hallo.

My original plan for this week was to gut all of the content from my previous game, extend the rendering capabilities, and make a new game; this hasn't happened. 

Instead I decided to stop dicking about with pseudo 3D stuff and mash out the full renderer (or at least the core of it) in a blitzkrieg of code and relentless. Animating simple trees and spiders had got me in the mood for some more procedural animating too, so I decided to trial-run  my new renderer with a procedurally animated robot-man. The code I used to move his arms and legs was very similar to the methods used on the spiders, with the exception that I extended the algorithm to accept more parameters, so a greater range of 2-bone relationships can be created. Thar she is:

Technical crap. 

One of the first things I did once stuff was drawing on screen was try to optimize, as it was hella slow. Aside from standard stuff like avoiding divisions, not assigning memory more often than necessary etc... the thing which really made a massive impact was switching from using Gdi's Bitmap::SetPixel(x,y,color), to using a unsigned char* to directly edit each byte of colour in memory.

Each frame the renderer draws to a bitmap, before drawing the entire thing to screen at the end of the frame. In the previous aberration I was drawing directly to the screen using lots of small rectangles for pixels.

As for shading, I decided that Gouraud was the way to go for now, especially since I actually want to use the renderer to make a playable game. This probably took the longest out of everything to get right, although when I started implementing the shading I didn't really know what I was doing either.

To create the human I made Model and Bone classes, with the idea that a bone can contain its own child bone. However I ended up just chunking a whole bunch of bones inside a MHuman : Model and writing the code for the animation directly into MHuman. In retrospect, had the ends of the legs and arms been child-bones of the top parts it would have made my life easier. This is right at the top of the todo list next time I make a model. 

The human is made out of lots of differently-scaled versions of the same shape, each created using the same function. Hardcoding even that simple shape (10 verts, 16 polys) took a long time, so I think all my future content will have to created in a highly algorithmic way... I mean, I could just make something in a nice 3d rendering package and write an importer... but y'know it just wouldn't be the same :P 

Massif props to Bob Powell, whoever that is, for explaining about locking and unlocking a bitmap's bits in his Gdi Faq.

Also massif props to Lukasz Pasek for many little tips on Gdi+ and shading!


AdiĆ³s

Wednesday 28 October 2009

Virtual Deconstructors!

Wow, turns out all the stuff I was going on about type casting was, while useful to know, unnecessary! When you delete a pointer of BaseClass* type which points to an InheritedClass object, all that needs to happen to get the base class to delete the inherited one correctly is to make the base class's deconstructor virtual. One word in the header file. Super easymode.

instead the VS2008 default of:

public:

BaseClass(void);
~BaseClass(void);

you have:

public:

BaseClass(void);
virtual ~BaseClass(void);

Thats IT!

Woo.

Monday 26 October 2009

I am finished with the building!

I am a naughty child :) I have allowed my weekend of coding to overflow into all of Monday. Good news is this little project is done now. Here's a little video of it in action:

Things that have happened:

  • Death sequence for trees and spiders. When they die, trees disappear segment by segment from the ground up because I thought it looked funny, and spiders go black and shrink... kinda like real spiders.
  • Rebirth! Tiny spiders appear and start running around, scaling back up to normal size over 15sec. Trees respawn as little stubs and scale up over 10 sec (while continuing animation).

As far as features go thats about it. Most of the time was spent on fixing bugs, finding and murdering memory leaks, and trying in vain to get better frame rates when fire is everywhere.

Since this has been my first real project using c++, solving all the errors and bugs has been great for developing my understanding of the language, one thing i thought was interesting:

Type casting. I had an issue where the program would randomly crash due to corrupted heap, the reason, I discovered, was down to some of my deconstructor code. In two places there were lists of pointers to a base class, which lots of things were inherited from. I would cast the children onto the base class and add them to the list. When I wanted to delete everything I iterated through the list and deleted all the pointers, however it was only deleting the inherited objects as though they were their parent class, so the actual deconstructors of the children never got called.

Turns out i needed to use typeid(...) to get the fully inherited type of the pointer, and then reinterpret_cast<...>(...) the base class pointers into their child types, before deleting them.

More next weekend!

Toodles

Sunday 25 October 2009

Nearly there, perhaps...

Phew, so thats officially the end of my weekend coding session. Incidentally its also the end of my weekend, so I didn't really have much say in the matter. A recent screencap of my creation:

Things that have happened:

  • Spaceship: hardcoded; weighs in at 16 polys and 24 lines. Gently bobs and rotates. 
  • 2D mouse point projected onto plane in 3D. The cursor has been replaced by a translucent square, the centre of this square is projected onto the 'visually accurate' position on the plane that is the ground (fps style). The position is used to move the spaceship, so that is it hovering above it. Essentially, mouse moves in 2D world across screen: spaceship moves in 3D above ground.
  • I got the formula for this by re-arranging the 3D-to-2D one, look at the previous post if you're havin a confuz, it looks like this:

_3dPoint._y = yPlane;
_3dPoint._z = (yPlane * FOCAL_LENGTH)/(_2dPoint.Y - VP_Y) - FOCAL_LENGTH;
_3dPoint._x = (_2dPoint.X - VP_X)/(FOCAL_LENGTH/(FOCAL_LENGTH + _3dPoint._z));

  • Tree animation! Re-engineered the algorithm so its prettier to look at. Individual branches move independently while the entire tree sways left and right, also the amount of movement increases towards the top, like a normal tree (it still looks like seaweed though).
  • Lightning! Click/Hold the Left button to strike the ground beneath the spaceship with a lightning bolt. Its pretty much just 2 lines each made of 5-6 points which get a new random x and z value each frame (y values preserved). Simple enough but it works ok.
  • Fire! Wherever the lightning strikes, burns. If it hits the bottom of a tree, the fire will spread up the tree. If it hits a yucky little spidery squit, that burns too (the fire travels with it on its back). Each fire burns for 5 sec.
  • Game-ish elements.... Every time you burn something you get a point :) As if you really needed the motivation.

At the moment there are some performance issues with the fire since it involves drawing a great many shapes and Gdi+ is slow. However there is one optimization that I haven't got round to working in yet, and it is very closely tied to a memory leak which took about a million trillion years to find:

Using Gdi+'s graphics.fillPoly(...) function, you need to provide it with a Gdiplus::Brush (which contains info like what colour to use). This was an unexpected turn of events when I was coding that particular section, and as such I only had a Gdiplus::Pen available. 'Ahh, not to worry' I thought, 'I can simply use the pen.GetBrush() function to retrieve a brush from the pen!'. Well it worked, but I didn't realise that it created a new brush each time, and I had written the GetBrush() directly into the arguments for the the fillPoly function. Every screen drawn was costing me memory!

Anyways, the final goal for this project now is for burnt things to die and new ones to spawn. Trees will grow to replace burnt ones, spiders will spawn very little and grow to replace their dead too. An ongoing simulation of burning strange creepy icky horrid little messes of a creature called spider, of burning peculiar wiggly fronds of seaweed, and of their subsequent rebirth. Great!


Toodles

 

Saturday 24 October 2009

It grows!

I haven't slept recently, and consequently my small spidery bit has grown into a larger multi-spidery-combination-seaweedy bit. The pic doesn't rly do it justice:

The 'trees', which is what I called their class although I prefer to think of them as seaweed fronds, have been procedurally animated too, so they sway gently in the breeze.... Well they did all sway the same way, but then I discovered it looked cooler if I de-synched the swaying, so now its more like they are being troubled by a gently troublesome tide. 

In addition I have given the yellow spiders a mind of their own so they just wander around sniffing about (insofar as a broken spider is capable of sniffing), within a predefined area. Not really sure where this is going next, mostly because vista restarted due to updates and murdered my todo list.

Technical crap - this is generally how it works so far:

  • GameObject is (sort of) the base class, and it contains basic stuff like virtual update functions and matrices
  • All high-level things that exist in the game(lol), inherit from the abstract Entity class, which in turn inherits from GameObject
  • Anything which inherits from Entity will contain a list for things which inherit from DrawnObject
  • DrawnObjects are also inherited from GameObject, and contain a list for Lines, and a list for Shapes
  • The spider is an Entity, it contains legs and a body, which in turn are DrawnObjects, made out of lines and shapes
  • The scenery is an Entity, it contains trees and the background, which are DrawnObjects etc.
  • When it comes time to draw the scene the entity class stuffs some pointers to the contents(lines & shapes) of its constituent DrawnObject list into a 'DrawPackage'.
  • DrawPackages hold pointers to things that want to be drawn, as well as the mean Z co-ordinate for that item.
  • The DrawPackages all get transformed by the relevant matrices before being shipped off to the DrawMachine, which waits until all are present before Depth-sorting and ultimately drawing them to the screen.

Dunno if all that makes sense..it's a rough overview anyways. Even though I set out to design it in a highly OO style I can see many things which I would like to have done differently, if I could be bothered to do it again... And I suppose I will be bothered to do it again since it's an assignment, ha.


Sayonara 

Friday 23 October 2009

Something small and icky

O hi, I was just in the neighborhood and thought I'd stop by for a quick chin wag.

Furthermore, a picture which doesn't speak anywhere near 1000 words:

We have to make a software renderer using GDI+/C++ for Intro to 3D, so I figured I'd go off on a bit of a tangent and make a horrible little skittely spidery thing that looks more like two horses duct taped together. Since its early days on the 'ole 3D rendering side I cheated, and used a different formula to project my 3d points onto screen space:


_scale3D = FOCAL_LENGTH / (FOCAL_LENGTH + _3dPoint._z);
_2dPoint.X = (Gdiplus::REAL)(VP_X + _3dPoint._x * _scale3D);
_2dPoint.Y = (Gdiplus::REAL)(VP_Y + _3dPoint._y * _scale3D);


Copypasta'd straight from the source mofo. Where VP_X and VP_Y are the coords of the centre of the screen, and FOCAL_LENGTH is 200 (it can be anything but values around 200 work best).

So far the little enginey thing supports drawing rectangles, ellipses, solid-colour-filled polys (up to 20 points), and lines. The little purpley thing is a spider with deep seated identity issues. Its legs are animated procedurally, although right now it can only run and be still (more to come!). I love making silly little creatures so hopefully soon you will see a field full of multicoloured animals getting Toblerowned (or possibly Sylvester Stallowned) by a small man with a club.

Also, massive props to Kenji-san for finally figuring out the Gdi-flickering issue.. he's making some variety of tetris clone using winAPI and thus is a very useful fellow.


Toodles

Wednesday 21 October 2009

Resident Evil Unreal Task

Watcha guise, heres some useless and sweet-tasting snaps of my contribution to our class's rendition of the resident evil complex. Yup. I made a corridor of all things.

It was fun carving out the world and playing architect. 

..but I wasn't really happy just making a long tube-like edifice so I added a cosy little room as well.

Snug!


The whole project came together pretty good,  however a quicker and cleaner solution for linking rooms up would have made the whole end-user experience about 1000% better. As it is you have to "click fire to play" on entering each room (with 5 sec wait).

Toodles





Tuesday 20 October 2009

Disassembling Jaguar Games...

...is a long and convoluted process it seems!

The best source for all things Jaguar I have found is the Jaguar Sever Homepage which contains pretty much everything a budding Jaguar hacker could hope for, unfortunately though if you're running 64-bit vista or windows 7 then hoping is about as far as it gets.

Sooo it goes a little something like this:

The Jag has three main processors, Tom, Jerry, and a Motorola 68000 who was picked on unrelentingly for his silly name. Srsly though, Tom contained the main dedicated GPU, in addition to the 64-bit object processor, and blitter chip (which is where the 64-bit ends). Jerry did all the bitch tasks like sound and Input whilst also being available for other non-specific stuff if the occasion called for it.

The 68000 was, and still is, a general 32-bit control processor.

This gives us quite a few disassembly options; however...While Atari ranted on about how developers could use the 64-bit blitter for all their logic processing needs this turn out to be a tad more involved or at least non-deadline-compatible than game devs at the time cared to be complicating their lives with. Consequently most game logic was processed on the 68000. 

For the sake of interesting times in assembly I decided to attempt to disassemble some of the 68000 code. 

If you are really eager and have already clicked on the Jaguar Sever Homepage link up there you'll notice the only option for 68000 disassembly seems to be a program called "easyrid4", which 'runs with' a Jag emulator (?); well it certainly wasn't content to run without one... The emulator Pacifist being the only suggested option I install it and discover that I am not DOS and that this just doesn't sit right with it. Not being one to give up that easily I crack open the DOSBox (a DOS emulator) and then attempt to emulate my emulator (ha)... Ultimately I am met with some variety of 'deferred success'.

I think I'll wait till I regress into a nice retro-friendly OS before having another stab at this, in the mean time there are plenty of  more popular retro consoles to satiate my disassembling desires.