Jul 23 2011

On the pleasures of memory management

Tag: Engine Designtrevor @ 12:38 pm

Error:  Allocation from MMO_GroundClutter.cpp line 42 was allocated using new [] but was freed using delete;  should have been delete []!

I can’t say how proud I was to have had my memory management system be smart enough to print out such a cogent and useful error message.  I’m less certain about how bright an idea it was for it to do the correct thing after displaying the error, instead of crashing immediately.  This error message, for example, has been generated by the game for three days now, and I only noticed it today.  If it had crashed immediately, I would have fixed it at once.

For those who aren’t familiar with the pleasures of C++, a large part of working with the language has to do with requesting and returning blocks of memory (by which we traditionally mean RAM).  We use those blocks of memory to store data temporarily.  Textures, models, various bits of gameplay, etc.  In C, there was only one way to get a block of memory:  you called “malloc()”, passing in the size of the data block you wanted to receive.  And when you were done with that data block, you called “free()”, the same way.

In C++, for various reasons, two more methods were added:  ”new” (for creating an instance of a C++ class), and “new []” (for creating a lot of instances of a C++ class in a big array).  Because these different blocks of memory contain different data and are allocated in different ways, they need to be freed in different ways.  For “new”, you must call “delete” to release the object.  For “new[]“, you must call “delete[]“.  In many memory management implementations, calling the wrong one will cause your program to crash, so it’s important to get this right.

VectorStorm’s memory management system isn’t a fast one.  I should say that up front.  When a game asks for memory, the memory management system does a pretty dumb linear search through its preallocated heap space looking for a spare area that it can hand out.  It also isn’t very memory-efficient;  it allocates extra space before and after each memory block that it hands out, storing information about how the block was allocated, by which file and which line of code, as well as boundary guards for detecting whether something has accidentally written past the end of the block.

These things all make it possible to easily detect issues like mismatched allocation/deallocations, leaks, and other places where programs have accessed memory incorrectly.  So every time I make a mistake about these things (which thankfully isn’t very often), it’s there to poke me with a stick.

It’s worth also noting that VectorStorm’s memory management also isn’t friendly to devices which want to use virtual memory (i.e. almost every modern computer or phone), since it handles all its own allocations inside of its own huge data block.  From the OS’s point of view, a VectorStorm game uses only a single memory block, which is several megabytes in size.  (In the case of MMORPG Tycoon 2, it’s currently about 600 megabytes in size, and will eventually be even larger.  Most of my other games are in the 6-30 megabyte range).

Between it’s lack of speed and lack of friendliness toward virtual memory support (or fragmented memory in general on the target device, as is often the case on, for example, the iPhone), I expect that for any major release I’d swap over to using the regular OS-provided allocation/deallocation functions instead of VectorStorm’s built-in ones.  But for the purpose of development, it’s great having a system like this there to catch errors early.  I know from long experience that it can be a real bear to track these things down otherwise.


Jul 06 2011

A long-expected fix

Tag: Engine Design,Full Games,MMORPG Tycoontrevor @ 11:37 pm

So this was a long time in coming.  For quite a long time, my procedural geometry generation system has been generating texture coordinates for the objects it makes.  This is so that (if/when desired) textures can easily be applied to the generated objects.

Texture coordinates basically work by assigning coordinates to each corner of an image;  the top left corner is (0,0), the top right is (1,0), the bottom left is (0,1), and the bottom right is (1,1).  What I’ve been doing is wrapping a texture around the objects I make, so the texture repeats some number of times, and the left and right edges of the texture touch each other.

The problem is that the vsMeshMaker utility class will not merge together vertices which have different texture coordinates — even if those texture coordinates are actually the same.

 

For example, in the image above, the top face of that cube has vertices with texture coordinates (0,0), (0.25,0), (0.5,0), (0.75,0), and (1.0,0).  (yes, there are five vertices defining the top face of the cube — the vertices for (0,0) and (1,0) overlap each other, and are only different for texture mapping purposes).

This situation was absurdly common;  two vertices which are exactly the same, except for the point in the texture that they’re referring to.  And even the texture coordinate is (technically) referring to the same point;  just expressed differently so that OpenGL renders the correct part of the texture map to the pixels around the vertex.  And the vsMeshMaker didn’t understand this situation, and so wouldn’t weld the vertices together.

The usual result of this (which was very common in MMORPG Tycoon 2) was that you’d get a strange lighting discontinuity along one edge of every object in the world.  In this case, there was a sharp line visible running diagonally along the top of the cube pictured here.  It’s been that way for months and months, and I’d basically been doing my best to simply look the other way, when taking screenshots.  At last, I’ve worked out how to get the vsMeshMaker to weld those vertices together correctly, without breaking the texture mapping.

Very pleased to have it working now.  And the answer made me feel silly for not having thought of it before;  don’t actually weld the vertices together, just pretend to have done so, and have the pretend-welded vertices check with each other to determine their final, welded normals.


Jan 08 2011

Code simplification

Tag: Engine Design,VectorStormtrevor @ 10:16 am

Old:

	float hw = width * 0.5f;
	float hh = height * 0.5f;
	// draw dark background
	vsDisplayList *list = new vsDisplayList(512);
	vsVector3D va[4] =
	{
		vsVector2D(-hw,-hh),
		vsVector2D(hw,-hh),
		vsVector2D(-hw,hh),
		vsVector2D(hw,hh)
	};
	int ts[4] =
	{
		0,1,2,3
	};
	int ls[5] =
	{
		0,1,3,2,0
	};
	list->SetColor(vsColor(0.0f,0.0f,0.0f,0.9f));
	list->VertexArray(va,4);
	list->TriangleStrip(ts,4);
	list->SetColor( vsColor::White );
	list->LineStrip(ls,5);
	list->ClearVertexArray();
	vsFragment *fragment = new vsFragment;
	fragment->SetDisplayList(list);
	fragment->SetMaterial( "White" );
	AddFragment( fragment );


New:

	vsBox2D box( width, height );
	box.Recenter();
	AddFragment( vsMakeSolidBox2D( box, "TestimonyButton" ) );
	AddFragment( vsMakeOutlineBox2D( box, "White" ) );

This is much nicer, innit? :)

Certainly it’s a lot shorter. Both create an identical box with an identical white outline. This is just using the new “vsMakeSolidBox2D()” set of functions which were recently added to VS_Primitive.h. I really ought to have more utility functions like these; they make it an awful lot faster to quickly prototype things!


Nov 21 2010

Bleah, sick

Tag: Engine Design,Full Games,General lifetrevor @ 7:18 pm

I’ve come to learn that being ill is an entirely different affair when you’re un/self-employed.  Far more stressful to be unable to work, when you don’t have paid “sick days” supporting you.

Yesterday I was basically unable to think straight, so ended up spending most of the day resting (and playing through the second half of “the Zombie Island of Dr. Ned”, in Borderlands).  It surprises me that that game has not yet hung a lampshade on how often it hangs lampshades on things.  But I still have two more bits of DLC to go through, so there’s still time. (I’m skipping the “arena deathmatch” DLC for now.  Not really feeling well enough to enjoy that sort of challenge at the moment.)

But today, I’m feeling a lot better.  Still not well enough to actually feel like it’d be wise to go out of the house and run errands, but better.  At the very least, my brain’s now working well enough to do a little coding again.

Continue reading “Bleah, sick”


Nov 17 2010

On the week

Tag: Engine Design,Full Games,General lifetrevor @ 10:30 pm

So it’s been a bit of a roller coaster week (and technically, it’s not over yet!)  Lots of ups and downs, thrills and excitement while it lasted, but in the end, I’ve basically wound up right back where I started.  No change to the work situation;  it’s tough to find a paying position this close to the end of the year;  everybody has basically stopped hiring until after the holiday period is over.  Will keep trying, though.

In other news, I’ve successfully converted the latest VectorStorm engine over to the iPhone.  This photo is showing an iPad rendering the same graphics as are shown in the Mac screenshot a few posts down (though here zoomed in, and tilted a little).  Those keeping track will note that this is the third time that I’ve ported the VectorStorm engine over to the iPhone, but this is the first time that I’ve managed to maintain the ported engine’s compatibility with PC and Mac builds, so the port can finally be brought into the live engine trunk.  This means that any future games I make can easily be compiled for all three platforms.  (Earlier games would have to be updated to work with the newer engine.  That wouldn’t be a very big undertaking.)

Additionally, I’ve finally succeeded at getting VectorStorm’s texture loading+rendering to work;  I’ve never managed to wire that up on an iPhone or iPad before.  (Each of the visible white lines in the photo is a “scribble” texture.  In retrospect, this wasn’t the best way to show off this “texture-loading” feature.  But it’s the only comparison shot I have.)

There are, of course, some caveats to the iPhone port, as it’s not quite complete.  These still-not-working features are:

  1. Haven’t yet reimplemented the sound or music systems for the iPhone, so no sound is currently supported on the iPhone.  (It won’t cause problems if you try to use them, it just won’t actually make any noise)
  2. Currently will only track a single touchscreen point.  Games query this via the sysInput system’s mouse interface.  I need to add support for tracking multitouch, so that I can handle pinch-zoom and other gestures.
  3. No proper interface for accelerometer data (there’s a nasty hacky way to get at that data, but since I’m not planning to actually use the accelerometer any time soon, I’m going to ignore this for now)
  4. No proper handling of screen orientation.  I’ll need to figure out the right thing to do, here.
  5. No support for shaders at all.  Even though the later iOS devices do support shaders, I haven’t set up VectorStorm to be able to decide whether or not to enable them under iOS.  For now, iOS is being treated as completely shaderless.  (It’s using the vsRendererPretty interface, rather than vsRendererShader or vsRendererBloom interfaces)

But it does support suspend/resume on devices which support that, and also supports the iPhone 4′s retina display.  Which is pretty neat to see in action.  :)

For those who are interested in graphics tech, there are also a few things which are disabled in the iPhone port, simply because OpenGL ES doesn’t support them.  These include setting different “blend functions” (proper support for subtractive rendering, for example), compiled OpenGL display lists, etc.  As with sound above, games which try to use these features won’t fail to compile;  those operations simply won’t be used.

I want to implement sound and music, and add support for multi-touch tracking.  Once that’s all good to go, I’ll pull all the recent changes to VectorStorm back into trunk.  (Sorry, Dan, I figured that it’d be better to wait and do the big trunk update all in one go, instead of doing it piecemeal, multiple times during a single week)


Next Page »