/* * Serious Port CHANGELOG. */ 10042001 - The porting (really) begins! Made a personal CVS repository to track my changes, and converted all the sources to Unix endlines. Wrote a perl script to change all the #pragma once lines to #ifndef blah/#define blah sections. Found out that Cygwin patch doesn't respect win32 newlines; ugh. Scratched together a basic Makefile, that tries to compile just DedicatedServer.cpp, which will keep me plenty busy for a while. :) Changed some cases of #includes, #ifdef PLATFORM_WIN32'd some other stuff, and just started pounding through the errors. What the hell is an .es file? They look like C code, with some intro chars...?! There's all kinds of Win32 API calls around the source, and use of things like POINT structs, etc...nothing I can't handle yet, but it makes me nervous; it's one thing to use Win32 apis, but when the headers themselves seem to depend on them, it's going to be a lot less clean to port this. Got rid of some of the usual culprits like _asm{ int 3 }...after tinkering and correcting minor things for an hour or so, I found I still had 1000+ warnings and errors just to compile DedicatedServer.cpp! Fortunately, most of these are in headers, so cleaning them up will result in less problems for the next source file. On the bright side, the entity class compiler builds and appears to work well...see how easy my life is when I'm handed code that was generated by GNU tools? :) Removed RobotFixed.es, as it appears to be an empty file. Updated #pragma once stuff to be more robust, at Alen's suggestion. Engine/Base/Base.h has all the Visual C specific stuff sectioned out now. Hacked out a perl script to automate the packaging of just changed files for shipping off to Croteam. *** (Source update sent to Croteam at this point, to test the whole merging system.) *** Put GNU C inline assembly versions of the math functions in Engine/Math/Functions.h, and left a section for portable C versions (and implemented them, where reasonable). Changed some "const iIndex" to "const int iIndex" in a function declaration in Engine/Math/Plane.h. Protected the DLL_DECL defines in various StdAfx.h headers (all these identical header names are making me very nervous). Added temporary typedef for HINSTANCE in Engine/Base/Types.h. (This will need abstracting at a later point). Other tweaks as needed. Engine/Entity/Entity.h has a conflict where they use enum DamageType before it is declared, which is fine on Visual C++, since enums are always degrade to 32-bit ints, but standard C permits enums to be smaller if the extra bits aren't needed, so there's no such thing as a forward declaration of an enum. Obviously, this is causing me trouble. For now, I've changed the calls to take ints, but I need to resolve some conflicts about getting the correct header plugged in there. I'm looking at Engine/Graphics/gl_types.h and praying that the Linux ABI extends to Win32. :) (Note that this was done over twenty four hours, with sleep and a physchology class in between...I just happened to start around 01:00 on the 4th. :) ) 10052001 - Replaced some byteorder swapping routines in Engine/Graphics/Color.h and Engine/Graphics/OpenGL.h ... Replaced some dangerous asm and named some anonymous structs in Engine/Graphics/gl_vertex.h. Removed the anonymous union in GLVertex4, since a class can't be safely unioned, (screws up vtables, etc) and short of a few bytes of memory, there's no problem with that change. More anonymous structs elsewhere. More win32isms. Made some really questionable changes to Engine/Math/Quaternion.h, involving templates and friends. 10062001 - Took my changes out of Quaternion.h, and just punted: I added -Wno-non-template-friend to the compile options. This fixes the warnings, but I wonder if this is generating incorrect code. My brain hurts. The OpenGL code isn't too bad for portability, but the audio classes are pretty much married to DirectX at the moment. I'll try and abstract this out, instead of wedging in a Linux solution right now, but for now, since the dedicated server shouldn't need this, I'm just #ifdef'ing things out. Down to about 81 errors in compiling my first entity, and I haven't even gotten through the headers yet (this is normal, I swear). Game/SessionProperties.h has a note at the end of the CSessionsProperties class that new fields should always be appended to prevent structure changes in savegames and demos. Ugh; that means that somewhere, there's an fprintf() or whatever that writes sizeof (CSessionProperties) bytes to disk, and that the (unpacked) structure is going to break on every new platform. UGH. I'll fix that, too. For some reason, my system's bison generates incorrect output from Parser.y (or maybe it's generating correct code from an incorrect grammar?) ...at any rate, I can build Scanner.l correctly, but not Parser.y, which is a real pain, since I need to fix a buffer overflow in the Parser. :) There's a ten-byte hex string ("0xnnnnnnnn") that is stored in a char buffer[10] variable. Yeah, no room for the terminating null char. On Win32, it just, by luck, works. Not here, though, so I'm patching the original bison output I was sent, too. Heh. (Actually, there's a LOT of these 10-char buffers in the parser...) WOOHOO! That fix got the first source compiling cleanly. Entities/Acid.cpp, generated from Acid.es, in this case. Actually, Entities/AirWaves.cpp compiled in the same run, so this is a testament to the fact that each file becomes a little easier as the surrounding infrastructure gets ported. *** (Source update sent to Croteam at this point.) *** 10072001 - Moved a bunch of win32 code from Engine/Base/Input.cpp to a new file called Engine/Base/Win32/Win32Input.cpp. I'll be the filling in the Simple Directmedia Layer implementation of CInput in (you guessed it) Engine/Base/SDL/SDLInput.cpp. Wrote an abstraction over DLL access. The interface is in Engine/Base/DynamicLoader.h, and implementations are in Engine/Base/Win32/Win32DynamicLoader.cpp, etc... Added a Sleep() method to CTimer (Engine/Base/Timer.h) and put its implementation into Engine/Base/Win32/Win32Timer.cpp. More of CTimer will be migrating into platform-specific directories later, but I wanted to get rid of the Win32 Sleep() call in DedicatedServer/DedicatedServer.cpp. Added a const char * version of CShell::DeclareSymbol, since Visual C seems to magically know to construct CTStrings from literal strings, but GCC doesn't. Added a basic signal handler in, and tweaked CSTREAM_BEGIN/END, and now DedicatedServer.cpp is compiling clean. Hey, does GameMP even get used? There seems to be some overlap with the Game directory, but very little seems to reference the MP version. I'll have to ask. I'm missing a bunch of needed headers from a directory called "Models", or I'm doing something really wrong, so I'm SOL for working on any more entities until that's resolved. In the meantime, I'm diving into compiling the engine itself. Started working on a filesystem abstraction for things like what sort of directory separators are used ("\\" vs "/" vs ":" ...), etc. Added an extra argument to SE_InitEngine(): argv0, which should be, literally, argv[0] from the mainline. Some platforms need this for determining the base directory. 10082001 - I'm fairly happy with the structure of the file system abstraction (Engine/Base/FileSystem.h), but there will be a lot of places to make little changes (most notably, hardcoded '\\' path separators). Engine/Engine.cpp compiles clean, some #ifdefs need to be replaced, still. 10092001 - Merged in latest Croteam tree. *** (Source update sent to Croteam at this point....which BOUNCED! ARGH! Acutally, it didn't. A forward to Alen's home box puked, but the original made it to his Croteam box. Whew.) *** Converted some new inline asm in Engine/Graphics/Color.h, and some anonymous structs in Engine/Graphics/Vertex.h ... this is the result of the new graphics engine changes (Direct3D support, etc), but it's cool, because Dean seems to have picked up on the USE_PORTABLE_C thing, too. :) Got the changes compiling as before, and plugged in the headers from the public SDK, to start tearing through the entities. These are mostly compiling, except... gcc doesn't like funccall(FLOAT3D(x, y, z)), where FLOAT3D is a class reference being constructed in place. However, doing FLOAT3D f(x, y, z); funccall(f) seems to work. There's about a million of these in the entities, usually with the ShootProjectile function. Also, Visual C is willing to call CTString::operator(const char *) when the CTString is used with a "%s" in a printf...gcc is, of course, not willing to do that unless you explicitly put the cast operator. That's the bulk of the entity work, followed by the occasional header problem. All the entities for The First Encounter seem to be compiling. 10102001 - My God, I think I managed to coerce the Makefile into building the .es files correctly, instead of trying to randomly remake certain ones (Shit...maybe not. It's better, but changing one .es make it rebuild them all. ARGH.) Added all of the Engine/Base/*.cpp files to the Makefile. Now the fun really begins. :) But FIRST...the stupid Makefile. I hacked out a perl script that lists out an explicit rule for each entity, which makes the Makefile huge, but hey, it works, so those rules are sitting in Makefile.entities, which is included by the main Makefile. This will make my life much easier for working with The Second Encounter entities. I went through the whole Engine/Base dir. With the exception of one or two really nasty files that I'm hoping I can do without completely (such as StackDump.cpp), the whole thing now compiles clean. There's a few stubs, some of which I'm not sure how to best handle yet, and some I'm too lazy to handle until forced to, which led to the nice STUBBED() macro in Engine/Base/Types.h. :) I'm putting more #ifdef PLATFORM_WIN32 lines than I'd like to, knowing fully that there's really no good way to clean some of those up. ...and this fuckin' __declspec(thread) shit has got to go. That is going to be a pain in the ass before it's resolved. Engine/Base/Synchronization.cpp has been moved to Engine/Base/Win32/Win32Synchronization.cpp, and I will implement an SDL version for Linux later. Wrote a perl script to replace all the #include "stdh.h" with the correct line (#include "Engine/StdH.h" or whatnot). Engine/Brushes directory compiled with almost no complaint. 10112001 - *** (Source update sent to Croteam at this point.) *** Quick case-sensitivy fix to scripts/stdh.pl. Engine/Entities dir is now compiling. I'm a little nervous about the presence of GUID's, but we'll see if it proves to be problematic in reality. There's a DLL lookup on what I think might be a class method, but I haven't really looked into that. I did see somewhere else in the source a mangled function name lookup, which is obviously not going to fly. Started on the Engine/Math directory. Mostly compiling, after writing some FPU control word manipulation assembly. More fun: What the hell is "Exploration3D", and what can I do without the source to what appears to be a pretty important library? This is used to load 3D model formats. Uhoh. Engine/Models directory now compiles clean. Engine/Light directory now compiles clean, with a bunch of stubbed asm to be rewritten. In plowing through the Engine/Graphics dir, I'd like to see an OpenGL class (with platform-specific context manipulation code abstracted), a Direct3D class, and a NoGraphics class, which would get rid of all the #ifdef'ing, checking what type of graphics are currently initialized, and the assertions to make sure that type is valid. Anyhow, with a million stubs and #ifdefs, Engine/Graphics is compiling. Engine/Network compiles clean, with a caveat in the gamespy interface for determining country; I'll have to see what glibc has for that. 10132001 - Engine/gamespy compiles clean. Alen says that 3D Exploration isn't needed for the client and server, so I've just removed the one Math source file (Object3D_IO.cpp) from the build for now. If there's symbols in that file I need, I'll play surgeon later. Most of the Engine/Rendering directory is .cpp files that are actually included like headers. That's kinda obnoxious, but once I weeded out the pseudo-headers from the Makefile, the other three sources compiled with little complaint. Perhaps not surprising, Engine/zlib went up without any fight. Realized that I had forgotten to add Engine/Base/CTString.cpp to the build. (Whoops.) There's a nasty ScanF hack that bypasses the this pointer on the stack before unconditionally JMPing into sscanf. This will need to change somehow...for now, I'm punting and trying vsscanf(), and hoping that works. After a lot of stubbing and #ifdef'ing in the Engine/Sound directory, I've got the entire Engine/ dir compiling clean! 10142001 - Game/ directory compiles. Now I'm starting the long process of sorting out duplicate and missing symbols, so I can link a binary. Implemented Engine/Unix/UnixFileSystem.cpp. I really want to change the CFileSystem interface to use CTStrings, now. Implemented Engine/Unix/UnixDynamicLoader.cpp, and fixed syntax errors in the Win32 versions of these files. Realized that there ARE a few files in the Engine/Templates directory that should be directly compiled. After adding one cast from (CTString&) to (const char *), They went up without a fight. Implemented platform-independent mutex support in Engine/Base/SDL/SDLSynchronization.cpp. Obviously, platforms that aren't reliant on SDL (win32, at this point) should just use their current mutex implementation. Dropped in the really simple Engine/Base/SDL/SDLTimer.cpp, which is just a wrapper over the SDL_Delay() function right now. Entities/Common directory compiles clean (missed that one; whoops), but there seems to be some zero-length .cpp files in there. I hope they aren't needed. I'm now down to 110 undefined references. Some of these are in flex/bison stuff I haven't compiled, some are unimplemented stubs (GL context management, etc), some are files I intentionally left out (Object3D_IO.cpp, etc), and very few need to be specifically tracked down. I'm seriously having no luck with the bison and flex generated code. I wonder what Croteam is doing differently than me, and I wonder if they updated their utilities, if they would still compile. I'm too inexperienced with flex/bison to explore the problem and too lazy to boot. :) 10152001 - Killed an unresolved symbol or two. Patched Engine/Base/Scanner.l and Engine/Base/Parser.y, and their equivalents in the generated source since I can't get them to generate right. This resolved some missing symbols. 10162001 - Fixed the Quaternion problem; apparently inline friend functions need to actually be inlined (as opposed to just using the keyword), or they won't resolve at best (even though the compiler doesn't complain), or will cause syntax errors at worst. This seems to be an optimization bug; other code (but not all methods using the inline keyword) had to be physically inlined in the class definition, or it wouldn't resolve at link time. Removing the "-O2" optimization flag at compile time seemed to fix this, but I'd rather have a little code moved into a header than give up optimizations (not to mention that inline assembly NEEDS the -O2 flag or it miscompiles. ARGH.) Removed Engine/Models/EditModel.cpp from the build, since it relies on Engine/Math/Object3D_IO.cpp, which relies on that Exploration3D library. This seems to safely handle some unresolved symbols. Added a very-stubbed Engine/Base/SDL/SDLInput.cpp. Routed out a buffer overflow in Ecc/Parser.y that was causing ECC to generate incorrect code (and therefore, reference nonexisting symbols). For reference, gdb's "awatch" command is still damned near useless. The best way to find an overflow in a static buffer is to add a condition to the source to check when a different variable appears to be clobbered, and have the debugger break when that conditional branch is hit, then start performing the autopsy. I added a "static int fuckedbuf[30]" to the source where the clobbered variable was, looked for it to change (and when it did, it had part of a human-readable string in it...good clue), and checked a counter for the number of iterations the main loop had tumbled through. Then, I changed my clobber condition to just check the counter for that number of iterations minus one and reran the program. Once I hit that breakpoint, I could just single step until the clobber became obvious. In this case, we were writing a 10 to 30 character (or so) string to a 10 byte static buffer. Whoops. :) The condition that caused code misgeneration was hit rather frequently; this dropped my unresolved symbols from over 100 to 20. Stubbed implementation of Engine/Graphics/SDL/SDLOpenGL.cpp. I'm down to FIVE missing symbols, and four of them are in a parser that I can't get to generate correct code. ARGH. Alen, however, being the psychic that he is, emailed me the pregenerated source files WHILE i was typing that last sentence. Amazing. :) Ok, one symbol to go. It's that vsscanf() call I put into Engine/Base/CTString.cpp on 10132001, so it looks like my punt didn't work. Ugh. Let me think on this...Aha. Needed an 'extern "C" {}' around the vsscanf() declaration to prevent C++ symbol mangling! The binary links! Started working my way through the crashes... :) 10172001 - Fixed Makefile to handle dependencies more correctly. Added a couple of methods to CFileSystem: IsDummyFile, FindFiles, IsDirectory. Debugged CUnixFileSystem, and CUnixDynamicLoader. Replaced AnalyzeApplicationPath() in Engine/Engine.cpp for the second time. :) Just discovered that ErrorReporting.cpp's ThrowF_t() not only forgets to call va_end(), but it throws a stack-allocated string buffer, which obviously doesn't work. This will probably need thread local storage to work correctly, or a global search for catch() fields to add a delete[] strerror, but I need to think on the problem. I need to send something off to Croteam soon. Today, honestly. I'm on a roll, though, and I hate to send half-working code when I've made this much progress. Changed DedicatedServer/DedicatedServer.cpp so that on non-win32 platforms don't require the user to hit return on the usage output. Added include-once blocker to Engine/Engine.h. Now uses CFileSystem abstraction instead of _findfirst/_findnext in Engine/Base/Directory.cpp and Engine/Base/Stream.cpp. Removed some STUBBED() sections in Engine/Base/Shell.cpp; the total memory reporting isn't needed, and is never accurate anyhow. Same goes for total disk space. Commented out _RTP_do's chattering for now, since it's all getting spit through CPrintF anyhow, from what I can tell. Downloaded amp11lib from Alen's webpage and got a very stripped down version of it building as a shared library for Linux. I haven't tried it, but it does successfully dlopen() and find all the symbols that the engine seems to expect to find, so we'll see if it works when I get to the client. The Ogg support went up without a fight using my system-installed library. 10182001 - I haven't found a way to handle win32 -> unix dir separator conversion (at least, I haven't found a way that I like), so I've started making changes, on a per-case basis, to use CFileSystem::GetDirSeparator() instead of hardcoding '\\' chars. We'll see if this bites me in the contents of a data file somewhere. Apparently CTStream allocates enough memory to hold an entire file, but doesn't commit the pages, so that there's a segfault when you try to "read" the file in memory. A segfault handler runs, determines that the touched memory was a file's page, and loads the next chunk into memory before returning control to the program, which reads the memory as if nothing happened. I see this as (I presume) less efficient than just fread()ing directly, which is what happens anyhow. If nothing else, it's nonportable, obfuscated, and overly complex. Not to mention, there's lots of platforms this won't work on, since it relies on a feature of a multitasking operating system, so if there were ever a PS2 or GameCube port, this same problem would come up. Under linux, there are some options. One, you can just punt and malloc() the block and fread() the whole file in one shot, then the rest of the code will "just work" presuming that you have enough memory to afford this. Alternately, you can mmap() the file, which is more or less what the win32 code is emulating. Alternately, you can try and duplicate the win32 behaviour using the same tricks that Electric Fence does. Or, you can do what I opted to, and #ifdef the win32 code, and just do fread()s, fseek()s, etc where needed (after all, a decent OS should make these efficient operations...including win32. I thought.). This seems to be the best solution for non-win32 platforms, and makes CTStream a good candidate for moving into the Win32/ and Unix/ dirs at a later point. The audio subsystem and the sound decoder plugins now return immediately at init time if running as a dedicated server. This is a little saved memory, but it's more important to not try to touch audio hardware on Linux for applications that don't need to do so. I'm finding a lot of code that throws a char * to signify an error, which is fine, except the array of chars is usually stack-allocated. Honestly, it amazes me that worked under Windows. For now, I've changed them to new char[arraysize] calls, so they'll be heap allocated, but they leak memory. Ugh. I'll have to think on this. Back to the file streaming thing; it's actually more complicated (!) than I made it out to be, and the system will need to be replaced for a console version anyhow, so it will be to be ripped out, which will be ugly. For now, I'm just malloc()ing the whole file at once, which still doesn't help if this is used for write access. ARGH. Fuck it; I put a conversion routine into Engine/Base/FileName.cpp to convert '\\' to platform-dependent dir separators on non-win32 platforms. I had to change CFileSystem::GetDirSeparator() to be static since there's a LOT of static constructors at startup time that need this conversion routine before _pFileSystem() can be initialized. What a shitty day. 10192001 - Made the CDynamicLoader subclasses more robust. Changed Makefile to generate shared libraries for the entities and game, and added a script named "b" to make building easier for my lazy ass. :) 10202001 - Found a bug in my _control87() implementation that was causing floating point exceptions. Fixed. Next problem is to figure out what to do with thread local storage. 10242001 - (Argh...I've been so busy this week. I hate that.) Initial implementation of CThreadLocalStorage is in place in Engine/Base/ThreadLocalStorage.h. Took out the STUBBED() call in IsValidFloat() and IsValidDouble(), since these are only used for debugging, and are hard to implement portably, so screw it. Fixed Engine/Base/SDL/SDLSynchronization.cpp, which seems to get the server to the point where it can answer (and then puke on) a connection, but at least the race conditions that were causing assertion failures are gone, so the server doesn't crash while sitting there idle. 10252001 - No, there's definitely a race condition in CBuffer; I put mutexes in there, and it seems to be okay, now. Not sure if this is something that Linux exposed, or there's some other problem. My system is having some issues with working as a server (as I've seen with ftpd and sshd in the past), which might be exasperating my problems. Plus having two CPUs in this box, I've got the possibility to execute two threads truely in parallel, which probably hasn't ever been tested with Serious Sam on a win32 box. Then again, maybe it's my fault. I ripped out the SDL-based mutex implementation, and put in a pthreads version, and the strange crashes and deadlocks seem to have gone away. I dunno. I'm fuckin' useless. 10262001 - Finally managed to actually fix a bug; there was no SIGINT handler, so CTRL-C was killing the process with extreme prejudice...adding this caused a segfault since the SDL timer never got shut down; also fixed. *** (Source update sent to Croteam at this point.) *** Just to see if it could be done, I started making the Serious Engine run on a single thread. This actually seems VERY doable, since the only thread spun is for timing purposes, but removing the thread means removing all the mutexes and thread local storage, which probably reduces latency quite a bit. Also, it would confirm whether I've got a race condition. :) I'll probably finish most of this work up tomorrow; #defining SINGLE_THREADED enables this, don't define it to keep the codebase sane. 10272001 - Aha. Network packets are sent like this: ...writebytes(&blockheader, sizeof (blockheader)); That's evil. Here's why. struct BlockHeader { SLONG x; CTimerValue y; } We'll look aside the potential for CTimerValue to change for a moment, since, by fortune, both GCC/x86 and Visual C decided that it's eight bytes long. SLONG is four bytes. Under GCC/x86, sizeof (struct BlockHeader) yields 12 bytes. Under Visual C, it's 16, since it added four bytes of padding between "x" and "y". The way structures SHOULD be sent across the network is field by field (a "field" being an intrinsic; structs should be broken down to their intrinsic components, too. Things with constructors should probably never be sent at all). This gives you the ability to avoid padding issues, and makes it convenient to swap bytes on the other end for bigendian processors. If you absolutely MUST send sizeof (struct ...) bytes, PACK THE STRUCTURE. It's too late to pack it once the game is released. I went through every structure in Sid Meier's Alpha Centauri this way when we ported it to PowerPC Linux, and it took several 12-hour days of trial-and-error to fix all the structures. Actually, packing the structures with #pragma pack() is easy, the trial-and-error comes from attempting to keep compatibility with existing code, since the padding needs to be added manually to match the whims of the compiler. (*shrug*). So, after the changes, BlockHeader looks more like this: #ifdef NETSTRUCTS_PACKED #pragma pack(1) #endif struct BlockHeader { SLONG x; #ifdef NETSTRUCTS_PACKED UBYTE padding1[4]; #endif CTimerValue y; } #ifdef NETSTRUCTS_PACKED #pragma pack() #endif ...obviously, that can be simplified a little. Or we could serialize all net structures before sending, or just break compatibility with 1.04 clients. Oh well. The latter is the only trivial solution, but I'm for #pragma pack()ing now and serializing at a later time. On a lighter note, the single-threaded mode seems to work. That simplifies debugging if nothing else. With the elimination of all the mutex contention and thread local storage, this might actually reduce latency quite a bit, but I really need to wait until the client is running to speak with authority on that point. 10282001 - Waiting for some win32-specific files to show up, since I want to get this compiling on Win32 for parallel debugging (that will help enormously with getting the networking issues flushed out). In the meantime, I'm starting on the client. Got SeriousSam/* into the Makefile, and ran scripts/stdh.pl on the directory. Hhm. Uses Win32 messages for the menus. That sucks. 10292001 - Got DedicatedServer building with Visual C (ironically, it was a Unix tool that prevented me from building. :) ), and started tracing out the network code. Found a small unrelated problem already; we're not converting Unix paths back to win32 when writing them to a stream (such as a network connnection to a game client); fixed. I #pragma pack()ed a few more structs, but none of them seem to have been culprits for my networking troubles, but since they've been identified as safe, it's better to pack them and guarantee it for the future. 10302001 - We seem to be getting different results from zlib when compressing the same data under Linux and Win32. Not sure which is right; the retail client waits forever for more data to show up when connecting to the Linux server, and complains that the CRC of the data is incorrect with the win32 server I built. Venturing a guess that there might be a (lack of) optimization bug, I built the Linux server with the -O2 command line, which makes the thing segfault almost immediately. I can't fuckin' win. 10312001 - Found another missing va_end(), and decided to just grep it... there were several of these missing in the source tree. I'm not sure if these are no-ops on Intel Linux, but they should be there anyhow for safety. The optimized binary's crashes were coming from having -fomit-frame-pointer in the command line arguments. I'm not sure why I thought that stack unwinding with no base pointer would work, and I'm not sure why GCC doesn't even blink twice when -fexceptions is used with -fomit-frame-pointer. Oh well. 11012001 - Initialized the SessionProperties class, which makes the data fit that of win32's a little closer. Started working on a compile option to allow the game and entity libraries to be statically linked, since there may be some subtle but nasty duplicate symbol issues (this works differently under Win32), and this helps flush them out. 11022001 - I give up on the dedicated server for now, but I'll come back to it. It doesn't make any sense to spin my wheels on it when I can be working on the client, so I spent some time trying to get the SeriousSam directory compiling. LOTS of win32isms here. They seem to disregard DirectInput (or, at least, the CInput class) for the menu system for some reason or another. Played the game of casting CTStrings to const char * for printf() style calls, and stubbed a bunch of code. This, unlike the countless hours of tracing through CServer, at least feels like progress. There's a few references to CControls in the Game library, which wouldn't resolve at link time unless I changed _pGame.gm_ctrlControlsExtra to be a pointer to a CControls object...this forces the linker to rely only on the vtable so that the methods can remain in game.so. Got the whole thing compiling; now I need a whole bunch of stubs implemented. :) 11032001 - Took out some warnings, filled in some initial SDL OpenGL code. Other fixes. 11042001 - Filled in more SDL stubs. I'm doing less clean abstracting and starting to shove #ifdefs in to get this running. I can clean this up later, if there's a desire to do so. Started inlining some of the MMX code I've been putting off. !!! explain LCD problem here. 11052001 - More inline asm stubs filled in. 11062001 - More inline asm stubs filled in. 11072001 - More inline asm stubs filled in. 11082001 - More inline asm stubs filled in. (*yawn*) 11092001 - More inline asm stubs filled in. Apparently my LCDDrawing fix left some unresolved symbols in the game DLL. Went through and cleaned that up more properly, so that _pGame->LCD*() is always explicitly referenced, except in SeriousSam/, where the symbols can remain, since there is no longer a conflict (but those functions just wrap _pGame->LCD*(), too, so they should probably be removed). Fixed a memory leak in Engine/Base/ErrorReporting.cpp's ThrowF_t(). (And yes, there's still more inline asm to convert. This is the never-ending job, I swear. Most of that is done now, but there's more to be done.) 11102001 - Changed all the LCD*() in SeriousSam/, too. Filled in and corrected some of the SDL code. Now dying in a strange assertion failure. (spent several days here poking at the code, but not full time, in my defense. :) Having a full time job again really sucks a raw dick.) 11162001 - Finally figured out what was triggering that assertion failure; it was GfxLibrary::go_hglRC; I never set it, since it's win32-specific, but some distant code branches differently depending on whether it's set to NULL or not. Set it to (void *) 0x1 (oh well), and the code magically began to function. If that isn't exhausting enough, I now have to start picking the bugs out of my inline ASM conversions. Found the first ones: an undetected duplicate symbol and incorrectly filled registers in UploadTexture_OGL()...The Visual C version has mov esi,D [pulSrc], and I had initialized %%esi with (&pulSrc)...one ends up with an address, and the other ends up with the contents of the address. This is a very error prone and non-obvious part of the work. I'm so tired. On a brighter note, members of the Linux community have started paypal'ing me cash for my work on this. Unbelievable. I mean, it's not going to pay my rent or anything, but it's amazing that there are people willing to put their money where their mouths are and prove they support Linux. I love it. Maybe Croteam SHOULD sell a retail version of the Linux client. Hhm. Put in a virtual keys and basic win32-style event implementation, killing of a ton of stubs in the SeriousSam and Game directories. Just hit another infinite recursion due to a duplicate symbol in game.dll throwing off the linker; that's it, I'm making this thing statically link to fix this stuff once and for all. Done. At least I know I don't have any odd bugs due to Linux's shitty dynamic linker now...er, until I start linking with GameMP and EntitiesMP, that is. :) Found somemore crucial checks in regards to hwnd variables being NULL; set these to 0x0001, too. Found some code in Engine/Engine.cpp that got botched during the 10092001 code merge (see, this shit comes back to bite you eons later. :) ) At this point, I've got the menu coming up, and not rendering even remotely correctly, but I can feel my way through the "QUIT" option (including the "Are you Serious?" dialog). The credits seem to be running, too, but there's just junk in the GL window right now. Shaved some opcodes off FastLog2 and some other inlines in Math/Functions.h. #pragma pack(1)ed the structs in Engine/Graphics/Vertex.h. In addition to the struct packing, I changed FlushArrays() (Engine/Graphics/Gfx_OpenGL.cpp) to call glVertexPointer() with the right memory offset between coordinates. 11182001 - Apparently, I changed FlushArrays() wrong. As a test, I filled an array of floats from the array of GFXVertex4 structures, and used that with glVertexPointer(), and poof! Perfectly rendered main menu, including the cool LCD panel animations. My mouse routines worked on the first run, too. Simply amazing. Now my shitty hardware locks hard on the game (and any other GL app), so I'm scrambling to find a more stable motherboard. In the meantime, I fixed my keyboard event code to work in the menus (stupid console key still doesn't, though). 11192001 - Got a backup computer from a friend of mine; installing Linux and a voodoo3^H^H^H^H^H^H^Hgeforce2 MX. 11212001 - Fixed some assertion failures in the menus. 11222001 - Now have a stable test box with 3D acceleration, which exposes issues of supporting a box that the program wasn't compiled on; notably, that I need to statically link SDL, etc, since the test box doesn't have these libraries installed. Therefore, I've changed the Makefile to build both statically and dynamically linked versions of the binaries, which satisfies the LGPL license on SDL, and lets people tinker with alternative versions of SDL if they please on a (presumably unsupported,) separate binary. Fixed a non-initialized loop counter in my own code in Engine/Base/Directory.cpp, which was triggering an assertion failure (it's hard to reference element -10034326 of a CStaticArray. :) ) Fixed assertions in the "Advanced Rendering Options" menu; it seems that some cvars were removed in the graphics subsystem when Dean did the Direct3D work. These cvars are referenced in Scripts/CustomOptions/GFX-AdvancedRendering.cfg, and causes the game to puke when they aren't found. I added them back in tentatively as harmless place-holders; I assume that The Second Encounter's data files just don't reference them anymore, but it's problematic for me. I haven't tried, but it looks like the missing cvars might be cleanly handled if assertions are disabled, too. At any rate, the Advanced Rendering Options come up now. Haven't played with it any further than that, though. I really need to send Croteam a codedrop. 11232001 - Reenabled the timer thread, which fixes a few things (models in the player selection menu animate, the message about what video card was found goes away, etc). Eventually, I'd like to plug in calls to the timer handler in single-threaded mode like I did for the dedicated server, so that the game is easier to move to console systems and we can remove the overhead of mutex contention and thread local storage. Wrote scripts/scp.pl and added "make scp" rules to the Makefile. Since the game is complaining about the GhostBusterRay not being included (another Second Encounter thing?), I compiled it in, and just added stubs for the needed parts that were commented out in PlayerWeapons.es...this got me into the game's intro. Converted the inline asm in PIXCoord() (Engine/Rendering/RendMisc.cpp) and AddElements() (Engine/Graphics/DrawPort_RenderScene.cpp), and now I've got the starts of the Technology Test rendering. Added in asm from PrepareTexture() (Engine/Graphics/Fog.cpp) and RSSetTextureCoords() (Engine/Graphics/DrawPort_RenderScene.cpp), and I get (surprise) texturing in the Technology Test. My RSSetTextureCoords() is actually broken right now, so I've reverted to the C fallback until I can parallel trace it with a Win32 binary. The C fallback runs at about 1/2 the speed of the inline asm version, but we're talking about 6 microseconds verses 3 on a 400MHz Celeron, so it's low priority. With the C version in place, I get what appears to be almost perfect rendering in-game. Cool. Started hooking up the in-game input routines. VERY buggy right now. 11242001 - Fixed a stupid bug in the CUnixDynamicLoader implementation. Implemented SDL joystick support (doesn't work yet). 11252001 - Fixed incorrect ASM in CLayerMixer::AddDirectional(). Fixed my single-threaded timer code somewhat. 11262001 - Enabled key repeat when not in-game (menus, etc). Changed my relative mouse input to SIGNED integers and now the mouse seems to work more correctly in-game. Frame rate is awful, and every now and then the view point seems to jump like Sam has decided to do a quick headstand. Exploring why, but not ruling out the fact that this system is ancient for the framerate issue. Fixed the mouse input again so that it doesn't drift. Tinkered with the GL context creation code to make it a little more robust. Filled in inline asm in AddColors() (Engine/Graphics/Color.cpp). Fixed a bug in inline asm in AddElements() (Engine/Graphics/DrawPort_RenderScene.cpp). Fixing that lets me get into the start of the first map, but an assertion fails while the camera is panning over to the temple, shortly after the rain starts. I'm hitting a ton of stubs now, though, so it's probably wiser to fix those before tracing the assertion, as they are likely related. Filled in inline assembly in CLayerMixer::AddDiffusionMaskPoint() (Engine/Light/LayerMixer.cpp). Gave up and used the C fallbacks for the other ones for now. And here's that assertion failure: CRationalEntity::SetTimerAt() (Engine/Entities/Entity.cpp) checks that the desired time is > _pTimer->CurrentTick(), but Lightning.es calls this with _pTimer->CurrentTick() + 0 more or less hardcoded. I hope this doesn't mean that Croteam is no longer compiling with assertions enabled, 'cause I don't see how that can always pass on that call. I changed the assertion to check >= rather than >. (*shrug*). Hit another assertion down this codepath almost immediately. (*sigh*) Fixed my cvar declarations ("BOOL" is apparently not a valid type; now using INDEX instead, like some other BOOLs do). Decided to bite the bullet and deal with CTStream correctly. I started ripping all the win32-specific methods out of Engine/Base/Stream.cpp and put them into (you guessed it) Engine/Base/Win32/Win32Stream.cpp. The places where there isn't a clean rip (such as the three lines to determine memory page size) ended up in a new abstraction (SE_PlatformInitStreams(), in that case). Left it ripped up and went to bed. 11272001 - Continued tearing up Engine/Base/Stream.*. Removed some forgotten dump-to-file debug code I had stuck in the network code. Changed CCompressor::UnpackStream_t() (Engine/Network/Compression.cpp) to not touch stream memory pages directly. Changed all occurences of "lenght" to "length" in the source tree, since it was driving me nuts. :) Added a UNZIPGetPos() function to Engine/Base/Unzip.cpp. Finished initial mangling of CTStream...I still think this would be better if I just ripped out the crazy segfault-to-load-more-data method...if nothing else, it would all be a lot cleaner, but oh well. 11282001 - Got the file routines done; seem to work...are much slower. Not sure if the extra time is due to hitting new codepaths that were skipped when I couldn't write files, though. Might be interesting to add a cvar that determines if file reading uses a ring buffer or just dumps the whole file into memory in one shot and let the memory constrained users use one and the rest use the other. I dunno. 11292001 - Bit the bullet and just used the original file routines with support for writing to disk added. It's a memory hog, but it's fast as hell and less complicated than trying to hack it up by platform. This got me controls and moving around (poorly) in the game. Every now and then, the camera jerks to an odd angle for a frame or two and then back to what it should be. It even did this in the intro; it looked like the planets decided to do a quick rotation clockwise around my screen. I fear memory corruption. 11302001 - Fixed some nasty keyboard issues; PeekMessage() was being called in-game (I assumed it wasn't) in addition to CInput::GetInput(), both of which I had pulling events from the SDL queue, so not only were each only getting about half of the keydown events, but the matching keyups weren't necessarily going to the same place either. Now everything goes through one function which always allows CInput to update its state before passing the event on to the caller. Also, the _aiVirtToKid was defined to take 256 elements, which isn't nearly enough; hitting the up arrow writes to element 273, for example. Changed it to hold SDLK_LAST elements, and everything is peachy. Keyboard works great now. Tried split screen for the first time by firing up the Oasis level, which is also the first time I tried a real game scenario under Linux. It worked, but it was SLOW...maybe 3-5 frames per second. All the printfs speeding across my encrypted debug connection probably didn't help the speed, though, so I started fixing the stubs it was hitting. First I filled in the inline ASM in RenderPlasmaFire() in the file Engine/Graphics/TextureEffects.cpp, and second, I went to bed. :) 12022001 - The camera jerking problem is related to the timer handlers. In preparing to track it down, I wanted to see how consistent the jerk was by breaking in SDL_GL_SwapBuffers()...oddly, once it started, it happened exactly every 20 frames. Since the timer handlers are supposed to fire every 1/20 seconds, this seems suspect to me. I made a quick change so I could disable calling the TimerHandlers at will by modifing a global variable in the debugger, and did so once the jerking started. Sure enough, the jerking stops when the handlers aren't called. This makes hunting this one considerably easier, since there's only 2 handlers: the "game" handler (mostly checks input devices) and the "network" handler...doing the same sort of trick in the handlers shows that the network handler seems to be the culprit. I'll have to trace this more later on. 12062001 - Put in an ugly hack to calculate CPU speed; Attempts to get the information from the /proc/cpuinfo "file", and failing that (which it will, if used under FreeBSD's binary compatibility layer), it can get this information from the SERIOUS_MHZ environment variable. Oh well. Sooner or later the engine will need to be made not to rely on CPU frequency (and the TSC register) if it is to be fully portable. Fixed the console key so it works. 12072001 - Started merging my codebase with the 1.05 sources. Code merging is enough to give you belief in God. I've been doing this for 12 hours straight, and I've still got more than 19,000 lines of diff output to sift through. I think I'm hallucinating. I wish my copy of perl would become sentient and do this merge for me. I can hear my keyboard clicking when I smack the keys, but otherwise, I can't really tell if I'm typing. Time for a serious nap. 12082001 - Took a sudden trip down to Charlotte at this point. 12122001 - Finished code merge. Overall, it was akin to untossing a salad. Also got the Shaders/ dir mixed in, and a stubbed version of the internal IFeel API (as opposed to the API present in the DLL that the win32 version expects to load; that will probably not happen, even though I _did_ put the library loading abstraction in place in case it does at some point). 12132001 - Worked on getting the merged codebase compiling. 12142001 - Got the codebase compiling. Fixed an uninitialized value in CTimerValue, and the main menu comes up again...SCRAMBLED! Looks like Dean's new graphics abstraction has the glVertexPointer bug I had fixed perviously. Part of the problems of merging the code was refixing things I had fixed before that never got into the Croteam codebase...this is the danger of a volunteer effort without a central code repository, I guess. (*shrug*) 12152001 - Fixed the glVertexPointer() call. Everything renders as it did. The memory corruption appears to be "gone", too. Good thing I tagged CVS with a final 1.04 build that reliably reproduces it; I'll need to attack that again later. Implemented some of the inline assembly in Engine/Graphics/TextureEffects.cpp. The more I do this, the more I'm thinking the best idea for later would be to move this inline ASM to an external file and assemble it with NASM, so that there is one unified source that can be assembled into object files for both Linux and Win32 (and BeOS?), and for non-Intel platforms, it can be ignored altogether in favor of C fallbacks or maybe Altivec-optimized code on the PPC, a 3DNow! version, etc. That's something to look at for the future, but for this work, what's there now is fine. It's just a lot of error-prone duplication, is all. Not to mention that, even though GAS syntax is probably more sane than Intel syntax, inline GCC asm is NASTY looking. (*shrug*) 12162001 - Finished off the metric ton of inline asm in TextureEffects.cpp. Got the C fallbacks compiling, too, just in case. Oh, what the fuck, I moved some of the inline asm in Engine/Sound/SoundMixer.cpp to an external .asm file and put the infrastructure in place for building it with NASM (and a cool perl script to figure out the external symbols for me). This is only needed for building on Linux, but it would probably be in everyone's best interest to move the win32 build to this, too, since it makes everything much, much more sane (see rant on 12152001). Started implementing sound support using SDL. 12172001 - Finished off first-shot sound implementation. Started running the program through ElectricFence again, and found two buffer overflows in CTString.cpp right off the bat. Some part or another of _pSound->sl_ClhAwareList is getting hosed, and becomes circular; CSoundLibrary::UpdateSounds() is falling into an infinite loop when I move the mouse over a menu item (although I did distinctly hear the menu item selecting sound before it did! w00t!). 12312001 - ARGH. The stupid assembly code I moved to an external .asm file is hosing memory; I forget to add a "ret" instruction to the end of the routines. fuck. Fuck. FUCK. Works much better now. :) 01012002 - Happy new year. Fixed a logic bug in my CopyMixerBuffer_SDLaudio() implementation, and the sound appears to be working like a champ. Changed SeriousSam/Menu.cpp to only list SDL (as opposed to EAX, DirectSound, and WaveOut) for audio output. Fixed a bug in the SDL mouse button handling. CUnixFileSystem reports the "user dir" as $HOME/.ssam instead of $HOME (this needs abstraction, eventually, for non SeriousSam games.) Started cleaning out writes to base dir (the SeriousSam.loc and log file), and placing them in the user dir instead. Changed the fourth parameter of MakeDirList() (Engine/Base/Directory.cpp), strPattern, to be a CTFileName & instead of a CTString &, since the pattern can have win32-specific directory separators in it, and CTFileName's constructor will do the conversion for a given platform. Changed all occurances of calls to MakeDirList(). Change a hardcoded filename's case. Passed sam_strIntroLevel through a CTFileName in StartNextDemo() (SeriousSam/SeriousSam.cpp), and poof! Intro and demos run before the main menu. Schweet. This game is SOOOO much slower with debugging enabled and optimizations turned off. I guess it's all the profiling code, etc, because I can't imagine that compiler optimizations alone would boost the framerate THIS much. I mean, it goes from unplayable to relatively fast on the 400MHz box when I rebuild with nodebug/optimizations. Odd. 01042002 - AHA! Two days of tracing later, I've figured out why the camera flips over on occasion: Apparently in Quaternion::ToMatrix() (Engine/Math/Quaternion.h), we add/subtract a bunch of floats to figure out the camera's perspective matrix, and sometimes that calculation comes out to something like -0.000000000000001. Apparently on Win32, this is rounding to zero, but on Linux, it's coming out as a very small fraction below zero...of course, when this negative number ends up in the matrix, it causes the camera to invert. The solution is to check for an "epsilon" value, something like "if ((val <= 10e-6) && (val >= -10e-6)) val = 0.0;". Instantly fixed the problem with the camera inverting. I assume the bug is also what causes Sam to look in odd directions in-game, but that went away on its own since I merged in 1.05, so that could still be memory corruption lurking instead (need to get 1.04 compiling again to verify...), or the opcodes got shifted around enough. Occasionally the clipping is messed, and you can see through many walls or get the "hall of mirrors effect" if you press your face against them...likely this is the same problem elsewhere in the codebase, and will need to be rooted out. At least THIS one wasn't memory corruption, so I can die happy. In other news, I've added code to make sure files opened for write end up somewhere under the userdir (which should be the application path under win32, but is more like $HOME/.serious in Unix). Files opened for read try the userdir first (and userdir+modname) before the base dir. 01052002 - Fixed the mousewheel to work (or, rather, enabled mouse buttons 4 and 5...there's no distinction under Linux). _mkdir() call in the screenshot code is commented out, now, since the new code I added in Stream.cpp does this for you. Cleaned up some DLL loading code. Added beta expiration code to SeriousSam/SeriousSam.cpp and the Makefile for later use. Fixed DLL loading of amp11lib (it doesn't use an absolute path, which was a problem. Fixed the command line arguments that get passed into the engine to not contain argv[0]. Engine/Engine.cpp notes that it's running under "Unix" in the console output. Tinkering in the SDL input code. Apparently the mousewheel is still not working. 01062002 - Fixed an assertion that was failing on valid data in Engine/World/World.cpp. Updated MakeDirList() (Engine/Base/Directory.cpp) to check the userdir before the other locations (and userdir+modname, yaddayaddayadda...) This allows the savegames to show up (they were writing to the userdir, but not being enumerated from there). Savegames don't actually LOAD, mind you, but it's a start. Actually got the mousewheel working this time. I think the timer is fixed, too, so it should keep sync even if the game goes off somewhere where it can't call the timer update function for awhile (such as while loading levels). I should try the multithreaded timer again now that the codebase is more stable, but I feel better without dealing with mutex and thread local storage overhead and other hard-to-trace potential race conditions. CCompMessageID::NewMessage() (Entities/Common/Common.cpp) compares against hardcoded patterns with win32-style dir separators. I've added CTString CTFileName::Win32FmtString(void) (Engine/Base/FileName.cpp) to deal with these occasional problems. This just makes sure a given file is in win32 format for such comparisons. 01072002 - The lighting is very wrong on some indoor parts, so I started looking for flaws in Engine/Light/LayerMixer.cpp. Found a couple of glitches and enabled some inline asm where I was relying on a C fallback before. Now some parts that were way too dark (black, in fact) are rendering correctly, but some other parts are still rendering way too bright (white, in fact). The bughunt continues. Fixed CUnixFileSystem to return the correct executable path when run from the $PATH and not from a specified path on the command line (it only returned the dir and not the filename; doh!). Removed my windowing short-circuit, so that fullscreenmode can be set. Removed some STUBBED() reminders that aren't relevant anymore. ShowCursor() and ScreenToClient() (Engine/Base/SDL/SDLEvents.cpp) were not returning values, which was causing an infinite loop when switching to full screen in the Video Options menu. This led me to the discovery that I'm not passing gcc the -Wall option (just -Werror), which explains why getting a clean compile wasn't as painful as I anticipated. :) Moved in some shell symbols that were missed in the 1.05 codemerge: sys_strModName and sys_strModExt (Engine/Engine.cpp). Removed #ifdef around IFeel deinitialization, for correctness. Debug builds just call SDL_PauseAudio(1) without calling SDL_CloseAudio() or SDL_QuitSubSystem(SDL_INIT_AUDIO)...for some odd reason gdb gets confused when SDL ends the audio callback thread and thinks the program itself terminated normally. No idea why. There's actually more overhead (the thread just feeds silence to the audio device during pausing, instead of relinquishing control of the device), so release builds should CloseAudio(). Also protected some audio calls that are made before an SDL_Init(). Hmmm...I was wondering when I'd find this (Engine/Parser.y): #define PUSHPARAMS \ memcpy(_alloca($3.ctBytes), _ubStack+_iStack-$3.ctBytes, $3.ctBytes); [...] PUSHPARAMS; ((void (*)(void))$1->ss_pvValue)(); ...that's utterly NONportable. It assumes the stack is layed out in a given way, and it assumes arguments get pulled from the stack. It will almost certainly break on PowerPC systems, where arguments aren't even placed on the stack if they can be kept in registers. Right now it looks like the values getting memcpy()'d are bogus in the first place anyhow, but I'll check it later, since it seems pretty rare to call a script function with arguments...Fixed an optimization bug in FillResolutionsList() (SeriousSam/Menu.cpp) where ARRAYCOUNT() was getting an incorrect value. Fixed up the C fallback for CLayerMixer::AddAmbientMaskPoint() (Engine/Light/LayerMixer.cpp) so that it compiles, which verifies my OTHER lighting bug is in the inline asm version (which isn't immediately obvious to my eyes, so the fallback is a winner for now). 01082002 - Files opened for writing would seek in the memory buffer, but not the (FILE *). I've added an override of Seek_t for CTFileStream on non-win32 platforms to handle this (Engine/Base/Stream.cpp). Now savegames work, since we're generating the .sav files correctly. Made DedicatedServer/DedicatedServer.cpp able to load the game dll regardless of from where the game was run. Looked at the ambient light code again. It looks like it's rendering some lights as bright white still, but I need to check the win32 version to verify. Added CD-ROM detection code, and changed some of the CFileSystem methods to be static (since the CD code needs them before _pFileSystem is assigned to). Took another look at the networking code. It's still fucked on Linux. I can't even serve to other Linux boxes right now (but, to be fair, the other Linux boxes are reacting to a Linux dedicated server precisely how the win32 clients do...stall out at 98% on one of the transfers. That's better than the CRC error I used to get, I think). Left a massive comment in Engine/Graphics/GfxLibrary.cpp about generating floating point lookup tables at runtime. Fixed CEntityClass::Read_t() (Engine/Entities/EntityClass.cpp) so that it doesn't need to see that Entities.dll is present to load libEntities.so. Same for the new shader library and the game.dll. Also, code should now be able to handle the new shader dll being statically linked (untested at this point, however). Tinkered with all the dynamic loading code some more, and now the entire game can run from CD (minus what it wants to write to the user directory, which can be a RAM disk if that's a problem). The binaries were on my disk (but wouldn't NEED to be), and this is problematic in that the data files might need patching, but just the updated/later .gro files could be on the hard drive and the rest on a CD. I'm rambling. It's bedtime. :) 01092002 - Free'd some leaked memory in the SDL audio routines; I wasn't freeing the decode and mixing buffers on shutdown/restart (Engine/Sound/SoundLibrary.cpp). Fixed audio at higher sample rates: we were always feeding SDL audio data 512 samples at a time, which the engine can't keep up with when the sample rate doubles and quadruples. Now the amount of data we tell SDL we're sending is scaled by sample rate to keep a balance between latency and underflow. Flipped an #ifdef in there that was incorrect, too (that damned NDEBUG double negative screws me up every time!). In talking to someone about thread termination confusing gdb, they recommended I go back from gdb version 5.0 to 4.18+linuxthreads patches. I did so, and not only does it work like a champ with the threads, the "awatch" command works, and using "TAB" for symbol completion doesn put GDB into an infinite loop that must be forcibly killed. I can't believe 5.0 has been out (and shipping with every Linux distribution) for this long when it broke so many important things. Allegedly, they are still broken in 5.1, also, but at least it looks like debugging just got a little more pleasant over here. I removed the #ifdef that prevents closing the audio thread in debug builds, after patching SDL (which was letting me open the audio device twice in those builds...no good). 01102002 - Added -ffast-math to the compiler command line in hopes that it might shift some opcodes around enough to fix the clipping bug (alas, it did not). Search continues. Added GCC profiling support to Makefile, but it seems to not work with this program. It just never outputs the profiling information at all for no good reason. I hate the GNU toolchain sometimes. 01112002 - Found a division by zero in the ray casting routines that was causing all sorts of trouble if Sam's gun was pointing straight down (Engine/World/WorldRayCasting.cpp). 04242002 - Intel Clipping bpp crash optimization of inline asm. /* end of CHANGELOG ... */