Jump to content
Search In
  • More options...
Find results that contain...
Find results in...


  • Content count

  • Joined

  • Last visited


About lucius

  • Rank
    Junior Member

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Thanks. To be clear, though, comments in most of the code aren't as dense. Generally, it is preferable to write "self-documenting" code and be a little more sparse with comments (since comments can go out of date over time and reduce the amount of code you can see at once). However, comments should always be used when the "how" and "why" of the code are non-obvious, as is the case with that particular function.
  2. Honestly, there is no magic to it - just a lot of tedious work, reading documentation, and puzzle-solving. :) It is basically a combination of disassembly + debugging in DosBox (for DOS-based games anyway, you can use Visual Studio for Windows programs). Most of the work is figuring out patterns, keeping track of all of your functions, variables, and structures, and constantly updating them with good names and types as you figure things out. For example, take this function: void obj_setupAnimation() { Logic* logic = s_curLogic; // eax logic->u68 = (logic->u68 | 1) & 0xfd; logic->nextTick = s_curTime + logic->delay; SecObject* obj = logic->obj; // ebx obj->anim = obj_getAnimationIndex(5); // eax -> edx obj->frame = 0; } You can see that most elements of the logic structure have already been figured out but 'u68' is unknown. So I have the name stubbed out (u = unknown, 68 = at offset 0x68 in the structure). Later I will see logic->u68 in action and figure out what it is used for, then I will go back and update the name. By updating the name, that will enable new understanding in existing code which will allow me to figure out other elements of the code (for example '1' is likely a flag, what does it do? Why are some flag bits cleared (the 0xfd)). Another big component, once you figure what the low-level code is doing is figuring out why. For example, take this function: s32 vec2ToAngle(fixed16_16 dx, fixed16_16 dz) { if (dx == 0 && dz == 0) { return 0; } const s32 signsDiff = (signV2A(dx) != signV2A(dz)) ? 1 : 0; // Splits the view into 4 quadrants, 0 - 3: // 1 | 0 // ----- // 2 | 3 const s32 quadrant = (dz < 0 ? 2 : 0) + signsDiff; // Further splits the quadrants into sub-quadrants: // \2|1/ // 3\|/0 //---*--- // 4/|\7 // /5|6\ // dx = abs(dx); dz = abs(dz); const s32 subquadrant = quadrant * 2 + ((dx < dz) ? (1 - signsDiff) : signsDiff); // true in sub-quadrants: 0, 3, 4, 7; where dz tends towards 0. if ((subquadrant - 1) & 2) { // The original code did the "3 xor" trick to swap dx and dz. std::swap(dx, dz); } // next compute |dx| / |dz|, which will be a value from 0.0 to 1.0 fixed16_16 dXdZ = div16(dx, dz); if (subquadrant & 1) { // invert the ratio in sub-quadrants 1, 3, 5, 7 to maintain the correct direction. dXdZ = ONE_16 - dXdZ; } // subquadrantF is based on the sub-quadrant, essentially fixed16(subquadrant) // which has a range of 0 to 7.0 (see above). const fixed16_16 subquadrantF = intToFixed16(subquadrant); // angle = (int(2.0 - (zF + dXdZ)) * 2048) & 16383 // this flips the angle so that straight up (dx = 0, dz > 0) is 0, right is 90, down is 180. const s32 angle = (2 * ONE_16 - (subquadrantF + dXdZ)) >> 5; // the final angle will be in the range of 0 - 16383 return angle & 0x3fff; } Where: signV2A is: signV2A(x) { return (x < 0 ? 1 : 0); } You can imagine, before the comments and some functionally equivalent changes this looked like a string of random math operations. Some things, like abs() hide a lot of underlying complexity in the assembly. But if you want to be able to fix bugs and extend the code in the future it is not enough to figure out what the code is doing, but you need to figure out why it is doing it. So having a good background in game/engine programming helps and of course some knowledge of assembly, though even then you will have to look up some of the more esoteric instructions every now and again. So it is a mix of tedium with spikes of puzzle-solving and head-scratching. After a while, you just start reading the assembly and just start typing the equivalent C-code. :)
  3. Closing the Game Loop The previous blog post talked about refactoring the code so that the reverse-engineered INF system, collision system, and renderer can all use the original, fixed-point level data. Another goal was to enable caching for systems, like the floating-point high resolution renderer, that need to transform the data in some way. It illustrated the connected nature of the core game and engine code . . . . Read the post here: https://theforceengine.github.io/2021/04/12/GameLoop.html
  4. I put up a new blog post regarding the state of the project: TFE Foundation and Test Release The Jedi Renderer and INF System have been completely reverse-engineered and the collision detection system is almost complete. But a new problem looms on the horizon. . . . . Read the post here: https://theforceengine.github.io/2021/03/19/Foundation.html
  5. The strange thing is that Dark Forces uses the same 70Hz video mode. I think the reason it isn't tied directly to framerate is that the Jedi Engine uses a "Task" system, where tasks can yield, run at specific rates, etc.. Anyway, game and INF code is split into these tasks with the idea that not everything needs to run every frame. In the case of the INF system, it doesn't really work - I mean the main update task runs every frame in almost every map, as does the texture animation task, but I think this is one of the reasons they chose more granular timer settings. For TFE, this is being greatly simplified since it doesn't really buy anything but the timing itself has to stay the same. That said, I didn't believe the 145 ticks / second thing at first, thinking I made a mistake. But you see it over and over again in the code, it is no mistake as odd as it is. :)
  6. You might want to read https://theforceengine.github.io/ and https://theforceengine.github.io/2020/05/05/firstpost.html to get an idea what The Force Engine is. You can see the blog archive here: https://theforceengine.github.io/archive.html. In summary, TFE is a fresh start, focused on accuracy using reverse-engineering, and is focused only on "Jedi Engine" games - Dark Forces and Outlaws. Dark Forces is the current focus but Outlaws shares a lot of the same code. The goal is for TFE to be a complete DosBox replacement for Dark Forces by the end of the year (meaning it is accurate to the original but does not use emulation).
  7. INF System and TFE Progress In the last post - TFE Update and 2021 Plans - I talked about the INF & Classic Renderer release which was to be followed by a “Player Control & Physics” release later in the year. Due to the way the renderer, INF and player controller are connected there has been a change of near-term plans. This post will go over those changes, talk about how the INF system works internally and provide a general update regarding the progress towards this year’s goal of reaching the 1.0 release. . . . . Read the rest of the post here: https://theforceengine.github.io/2021/03/02/InfSystem.html
  8. TFE Update and 2021 Plans As the first blog post of 2021, this will cover several topics. First, an update regarding the progress of The Force Engine. That will be followed by TFE plans for 2021 - the year of the first fully playable release (hopefully), and finally the first “experimental” build and what that is all about. . . . . Read the post here: https://theforceengine.github.io/2021/01/18/TFE-Update-2021-Plans.html
  9. In other news, I have moved on to INF reverse-engineering. But before I did, I decided to add optional perspective-correct texturing support to 3DO rendering. It uses "affine spans" to speed up the calculations in software, similar to Quake and similar engines. The length of these spans is computed based on the current virtual resolution. For example, at 200p perspective correction only occurs every 8 pixels whereas at 1080p it is every 32 pixels and at 2160p every 64 pixels. Here is a short GIF showing the comparison: I tested the results in one of the larger mods, Dark Tide 4, and took some screenshots and GIFs. These are running in the software renderer at 1080p with perspective correct texturing enabled for 3DOs: And a large GIF: If you haven't read it already, the most recent blog post is here: https://theforceengine.github.io/2020/12/27/TFE-Classic-Renderer-Complete.html You can also see a list of archived blog posts with recent news here: https://theforceengine.github.io/archive.html
  10. The Force Engine is focused on the Jedi Engine games - so Dark Forces and then Outlaws. The Force Engine will remain a focused project and I will not be adding support for any other games,etc. until Dark Forces and Outlaws are completely playable and the modding tools are ready. And for these kinds of projects, TFE will remain the sole focus - I don't have enough bandwidth for multiple large-scale projects at once. I haven't given up on the possible idea of a proper reverse-engineered "X Engine" port in the future (Future Shock, Daggerfall, etc.) - but that is a different project and in a distant future (if it happens). That said, I think Daggerfall Unity will work well for you. :)
  11. GIFs can be big, yes. But it is nice for some quick animations that play well in the browser - great for forum or blog posts. Obviously, GIF recording is no replacement for proper videos. Currently, the engine is set to record at 15fps and I usually record them at 640x480 in order to manage the size.
  12. I'm glad you liked that type of content. :) At some point, I have to continue the Dark Forces DOS rendering series. @VGA - I recently added GIF recording to the engine, so I decided to use it to show the 3D object rendering in the Classic Renderer, as you see here. So it is now almost as easy to record GIFs and it is to take screenshots.
  13. I posted a final blog entry for 2020, the Classic Renderer is finally complete - just in time to end 2020. TFE Classic Renderer Complete The 3D Object rendering system, derived from the original DOS code, is now working in both 320x200 (fixed-point sub-renderer) and at higher resolutions and in widescreen (floating-point sub-renderer). This completes the Classic Renderer reverse-engineering and integration project, allowing me to move on to reverse-engineering the INF system. . . . . Read the post here: https://theforceengine.github.io/2020/12/27/TFE-Classic-Renderer-Complete.html
  14. TFE One Year Anniversary The Force Engine started out life as DarkXL 2 on December 21, 2019. Two months later, the project was renamed to The Force Engine, in order to encapsulate the intent of the engine, and put up on GitHub. After another month of work, about 3 months from the beginning, The Force Engine was announced on DoomWorld. . . . . Read the post here: https://theforceengine.github.io/2020/12/21/TFE-One-Year.html
  15. To be fair, while I do think the port of Dark Forces to PSX was worse than the Doom port, my comments were less about criticizing the port and more about explaining why I don't see any need to add support for it (except for music). Or to put it another way, I consider the DOS version to be the basis for the Dark Forces reverse-engineering/port in TFE - though I think there is some value to making the good parts of the Mac and PSX ports usable at some point (some higher resolution assets for the Mac and the music for the PSX).