Posts Tagged ‘Quake’

Garbage Collection Redux

Sunday, June 8th, 2008

OK, so I’m back to NSAllocateCollectable as my weapon of choice instead of using NSMutableData objects. I was getting weird errors with NSMutableData here and there so I thought, well, why not see what was actually wrong with my NSAllocateCollectable implementation?

The problem I was having that loading a large map would completely blow out my 2 GB of RAM and stall the machine. That didn’t seem right for a Quake map. So I looked into it and the problem was two things.

First, the garbage collector wasn’t getting any time to run during the map load sequence. So while I’m creating verts and brushes and planes like crazy the GC is sitting there patiently waiting for a processor break to do it’s job – which doesn’t come until the end. So I stuck in some strategic calls to [[NSGarbageCollector defaultCollector] collectIfNeeded] and that’s happy now. Map loading only allocates a few hundred MB in total.

Secondly, my render array implementation was doing a lot more work than it needed to. What I wrote for speeding up rendering was an array of vertices, uv coordinates and colors represented by a blob of float data in RAM. It allocates a new blob within the greater blog for each new vert/uv/color that the editor wants to draw (these are grouped by texture, so all of the verts that use the same texture are drawn as one OpenGL call). It tried to optimize performance by keeping a chunk allocated that represented the maximum number of verts that were ever requested for that particular texture. This meant that it could save itself from allocating the data blob every frame for every texture. The trouble was that when it came time to resize the array to accommodate more verts, it wouldn’t allocate very much so it was constantly resizing the array during a map load. This ate time like crazy. Once I changed my “grow array by” value to something much larger, it took maybe 45% off of the load time for large maps. It wastes a little more RAM now but since we’re talking about a few hundred MB at the most here, I’m not concerned.

So I’m fully garbage collected now. Hooray!

More QBSP Work

Friday, May 30th, 2008

So I decided to take a look at multithreading QBSP since I already set up LIGHT and VIS to do it. In looking at the code, it seems Carmack set it up to fork() the process twice instead of threading the hull building. I assume this is because QBSP uses a ton of global variables which makes threading a major hassle without a lot of code refactoring.

At any rate, this worked straight away on Mac OSX once I enabled that code path. What that means is that ToeTag’s QBSP will build all 3 hulls (small collision, large collision and drawing hulls) simultaneously instead of sequentially. It’s not a huge savings but, hey, it’s something right? It was getting nasty with my remix map which now takes upwards of 30 seconds to QBSP itself. That’s been cut down to about 17 seconds now so I’m happy!

Oh So Close…

Monday, May 26th, 2008

Hey, my latest idea shows promise! At the very least, it’s screwing up far less than anything else I’ve tried. Below is a picture to better illustrate what I’m doing. The mesh on the left is what you’d see in ToeTag. It’s a concave mesh created in Cheetah3D and imported into ToeTag from an OBJ file. Quake won’t compile that shape as it is. However, once my deconstruction routine runs you’ll get what you see on the right – each convex chunk has been successfully split off from the original mesh and any holes created during the process are covered with new polygons. So in this case we get 3 convex brushes from 1 concave mesh.

This deconstruction magic will happen when you save your level and will be completely hidden from your view. All you will know is that you have complicated concave meshes in your level and somehow Quake is compiling and using them. It’s magic!

Now, the post title is correct. It’s close. It doesn’t work 100% yet as there are meshes that will screw it up and it doesn’t do well if the mesh is complicated. However, it’s coming along. I expect another couple of swings at the ball here and I’ll have it working well enough to call it a real feature!

When it’s working 100% I will give a full technical break down of what I’m doing in terms of code and algorithm (for those who might be interested).

For now, here’s another mesh being broken down properly. This one is a little more complex and has an embedded light source:

A Journey Of Triangles

Sunday, May 25th, 2008

I’ve been to the brink of hell and back and it doesn’t work yet. YET! I am determined, however.

Just to recap what’s been happening here – I’ve been trying to work out the code necessary to allow me to import triangle meshes into ToeTag and then have them successfully compiled into the map. What do I mean by a triangle mesh? For example:

Now, here is that mesh in ToeTag:

So, as you can see, ToeTag can import triangle meshes and use them just like regular brushes.

Now comes the hard part : now what?

Direct Insertion

What I tried first was to modify QBSP to read those triangle meshes from the MAP file and insert them into the BSP file directly. This proved very challenging due to QBSPs reliance on brush data being convex and sealed (meaning, no missing faces). I could get this sort of working but it was never 100% and there were huge problems with collision.

Decomposition

Then I thought that what I would do is figure out a way to break the mesh down into several convex brushes and write those brushes out to the MAP file to simulate the user actually creating them. This seemed nice because it was entirely within ToeTag and QBSP wouldn’t have to change at all.

I built a bunch of code including a routine that created secondary arrays showing me which triangles shared edges with other ones (my main idea was based around walking these edge connections to create convex chunks). This proved to be even more challenging because every time I thought of something I could almost immediately think of a mesh shape that would break it. No, this wouldn’t do either.

SKIP Faces

My latest idea was to extend the idea of SKIP brushes to individual faces. What this would entail would be having ToeTag take every triangle on the mesh and create an entire brush from it (like some of the OBJ utils have done in the past for Quake engines). It would then give the extra faces it created a texture name of SKIP and then QBSP could compile the BSP as normal but then throw away the SKIP faces before actually writing out the BSP.

While it’s somewhat easy to handle SKIP brushes, SKIP faces seems more challenging. I eventually got it to the point of being able to compile and remove the faces but the collision was never right as it was still relying on getting convex data fed to it. It was REALLY close though and was the best shot I had taken so far.

The trouble was the that resulting BSP, even though it had the SKIP faces removed, was so sliced up that it was killing VIS. I had a single room with 2 triangle arches in it and I was looking at a 60 second VIS. Not good. I rebuilt that same room using manually created brushes and VIS took less than a second. So this wasn’t going to fly.

So now what?

Well, now I’m back at the my Decomposition idea but with an entirely different algorithm in mind. It’s deceptively simple in my head so hopefully it will be equally simple to implement. It might work. But I won’t know until I try!

At the very least, I can say that this has been a real challenge for me and I hope that I’ve grown a little as a coder by going through it. The end is in sight. Whether than end entails me throwing in the towel or this idea working remains to be seen. Let’s hope for the latter!

Triangulation Of My Heart

Monday, May 19th, 2008

I’ve spent the last week or so trying to convince QBSP to accept raw triangles. This has been challenging to say the least and what’s funny is that it -almost- works. Almost. The problem is that the triangles are not being added into the clipping hulls correctly so they don’t block players, weapon fire or monsters. They do, however, appear in the drawing hull and Quake happily draws them for me.

There are other problems as well like – if the triangle mesh I’m feeding isn’t convex, it doesn’t carve into the existing BSP correctly (convex meshes work fine).

It’s all very shaky and almost-working-y but I think I’m going to take a step back and take another crack at dissecting the mesh myself before saving out the MAP file. What I mean is that I’ll take the imported mesh and break it down into convex shapes and write those out individually to the MAP file.

To that end, I’ve spent the weekend solidifying my CSG and math routines to the point where I’d be tempted to call them “rock solid”. I can’t find any maps now that display artifacts when loaded so that’s a good sign. I would sometimes get stray polygons shooting off into infinity and stuff like that but that all seems to be fixed now and happily working.

I’ll post another update once I’ve had a chance to throw these new math routines at some mesh dissection concepts I have bumping around in my head.

E3M4 Progress

Sunday, April 13th, 2008

A quick shot of what I’m doing in my E3M4 remix. What lurks in the towers above?

What lurks above?

E3M4Rmx – Progress

Monday, March 31st, 2008

Here’s a shot of my in-progress remix of E3M4. It’s coming along but there’s a lot of work still ahead of me.

-: CLICK FOR SHOT :-

Quick Groups & Prefabs

Sunday, March 30th, 2008

I finished implementing Quick Groups today in ToeTag. It’s really interesting to me how I figure out the features that the editor needs simply by using it. I was constantly having to copy things like light fixtures or complicated wall structures and other things made of many brushes/entities. This sucked a lot because I had to reselect everything from scratch.

With ‘Quick Groups’, if you are diligent from the start of your map, you’ll be sitting pretty once you reach critical mass of detail. Every level designer knows what critical mass of detail is. That’s the point in the development of your map when you’ve established the visual theme and now you’re heading for the finish line. You’re working on gameplay and new areas but the visuals are more or less established. With ‘Quick Groups’ you’ll be able to copy complex brushes/entities from earlier in your map without a hassle. You select one brush/entity, hit CMD+OPTION+G and then all the other brushes/entities that are part of that quick group are selected.

It does smart things too. If you copy a group of brushes/entities that are part of a quick group, the new brushes/entities that are pasted into the map will be placed into a new quick group automatically so they will be selectable as a group as well.

Creating a quick group is easy as well. Select the brushes/entities that you want to be grouped together and hit CMD+G.

This is hugely powerful once you get the hang of it. And I’ll go even further and say that it’s more powerful than a prefab system. There, I said it.

Prefabs are a great idea in theory but when it comes to Quake levels you tend to customize things in every level. Your prefab library tends to morph to keep up with your current levels requirements. So you might as well use quick groups and work within the level itself.

And let’s face it – level designers like designing levels. They don’t want to use a bunch of stuff that someone else built. They want to build it themselves.

Sure, sometimes you need something standardized like a slipgate or a teleporter. If that’s the case, just open another map in ToeTag, copy and paste what you need. Prefabs be damned!

BSP Blues

Sunday, March 30th, 2008

I decided to try something out yesterday. I’m trying to figure out how to get an OBJ file to integrate with ToeTag in a seamless fashion. I had many ideas but then came up with the one that I felt was ideal : have QBSP simply insert those triangles directly into the resulting BSP! Why fool around with trying to create convex shapes from the OBJ file or extruding the polys backwards or other techniques that can get messy?

Well, because the QBSP code is horrifically complicated. Well maybe not for some people but for me, it is. I can’t make heads or tails out of what Carmack is doing in there. Global variables everywhere, obscure variable names, oddly structured function calls – ye gods. So that idea is dead. I thought that I was close at one point as I had it reading the triangles in and I was inserting them into the BSP but lots of stuff was breaking and they weren’t rendering and … well, just forget it.

I’m going to do a more traditional implementation of it now. ToeTag will read the triangulated mesh into the editor, break it down immediately into a set of brushes and then you can work with it freely.

I will offset the pain of this somewhat by implementing a feature that I will call “Quick Groups”. You’ll be able to select a set of brushes, hit CMD+G, and then those brushes will work as a group. If you double click on one, it will select all of the others in the quick group. Any imported triangle meshes will automatically go into their own quick group. Should work well enough I suppose although I really would have liked to have gotten the QBSP solution working. I guess that’ll have to wait until someone who speaks Carmack better than I do can take a look at it.

Quake Remix

Friday, March 28th, 2008

So I can’t decide on anything to work on at the moment so I’m taking part in a fun little project over at func_msgboard. We’re remixing various Quake maps. Remixing means different things to different people but for my part I’m going to add a bunch of detail, optimize as much as I can, add a few secrets and maybe a few small additional gameplay areas and call it done.

For my part, I’m doing a remix of E3M4 (Satan’s Dark Delight). I’ve always loved that map but felt that it was somewhat lacking in the visuals department. Hopefully I can make some improvements on id’s original work!

Oh, and I think the email stuff is sorted out. Maybe. *sigh*