Re-implementing an old DOS game in C++ 17 (2019)
lethalguitar.wordpress.com
lethalguitar.wordpress.com
The developer put in a tremendous amount of work!
The wonderful thing about programming, is how the product of your intense focus can be shared with so many people. There are people who have built super detailed model railroads but you will never see them unless you visit their basement. With software, just about anybody can build/run/play this game that has been so lovingly and painstakingly recreated.
So much, this - I've occasionally gotten the opportunity to rewrite a piece of software and it is always a much better design the 2nd time.
I find it harder to see code all at once though (some IDEs have an "outline" of all variables and functions, but my current editor does not), and I wish there were more ergonomic ways to rearrange the order of things in code.
"To think, you have to write. If you're thinking without writing, chances are you're fooling yourself. You're only pretending to think." [1] Leslie Lamport
Jim Coplien on how one of Dave Thomas' companies do software [2]:
"They build a prototype, then they throw it away. They learn from the prototype. Then they build the product, and throw it away. And then they build the deliverable; and ship release 1, release 2, and release 3--and throw it away. Every third release, they are throwing things away. Do you think they have any problems with technical debt?"
[1] https://en.m.wikipedia.org/wiki/Fred_Brooks
[2] https://www.youtube.com/watch?v=gPP7Bleg214&t=2339s
[3] https://en.m.wikipedia.org/wiki/David_A._Thomas_(software_de...
After he talked about throwing away code, he started hammering on the idea of understanding your domain. I don't think you can program without rich domain knowledge, if you are, then the software you write is very narrowly focused.
My idea of programming has shifted quite dramatically over the last couple months towards almost a hyperfocus on the domain, the data representation of that domain and the hierarchy of abstractions that we use to represent the ideas in the domain and the physicality in the data (and some extent the algorithms).
A computer program is a great way to let you know that you still have parts of the domain to understand.
We should be working in systems that are finely tuned TO the domain, so that we can play with concepts as easy as declaring self evident facts, so that we can constantly be throwing it away.
> My version (...) has to convert the data into formats usable by modern video and audio APIs (...) in an endian-independent way, and adds quite a few correctness checks (...) instead of triggering undefined behavior
> the original can basically do a memcpy to show something on screen, I need 1000 lines of OpenGL code…
> I don’t have global variables, but this in turn means more boilerplate to inject dependencies into objects on construction etc.,
> I try to be fairly type-safe, which sometimes means needing more code, additional data transformations etc.
Here are some of the issues I've run into so far:
- Having no access to the STL (which would be too bloated for the PS1) makes many C++ features unusable. The ones that do not rely on the STL, such as virtual methods for I/O drivers or constexpr for compile-time string hashing, are still useful though.
- The PS1 is, very roughly speaking, a slow CPU with a bunch of fast ASICs bolted on. Most of those operate asynchronously but require relatively high-bandwidth streams of data (display lists, textures, geometry, audio...) that has to be generated by the CPU in real time or provided by another peripheral such as the CD drive. Feeding multiple ASICs running in parallel is an exercise in buffering and synchronization.
- As if that wasn't enough, most peripherals have their own proprietary data formats: the GPU uses a nonstandard 16-bit RGB color format where the top bit is used to enable alpha blending, the audio mixer only supports a custom ADPCM encoding and so on. I had to roll my own tools to convert assets into these formats ahead of time.
- Coroutines or threads are usually not an option since context switching burns a significant amount of cycles. A lot of "magic" has to happen within interrupt handlers, but those must also be fast since IRQs occurring before the handler returns are occasionally dropped.
- The PS1 has a BIOS that provides APIs for accessing files on the CD and memory cards, but they are so limited and bugged that I was pretty much forced to reimplement a full filesystem stack, from the SPI driver that handles communication with controllers and memory cards all the way up to the VFS layer. And writing asynchronous filesystem drivers without even using coroutines is... not fun.
Few. Because:
1. There are independent libraries implementing facilities from the STL for embedded settings.
2. The ones without independent implementations are very often ones you shouldn't be using in the first place, because they're slow in general or for your specific testcase (e.g. std::unordered_map come to mind - abstractly, very useful structures; but the STL interface+implementation is junk, performance-wise).
3. You have EASTL if you _really_ need it.
4. The STL is mostly data-format-neutral in the sense of not supporting any data format itself :-P
This looks like a really cool project.
Mostly I want to win the lottery so I can sponsor someone to code Sid Meier's Alpha Centauri in a modern vector/HD UI and with 64bit memory space.
Perhaps the FreeCiv guys would be up to the task if the price were right.