Wednesday, December 31, 2025

From OpenGL to Vulkan

In my last update, I decided to start learning something called Vulkan, or Vk for short. What's Vulkan, again? Why, it's just the hottest new way to put your graphics card to use!


I began climbing the Vulkano (so to speak) in 2023, but despite releasing multiple Vk-powered minigames since then, I'm still climbing it over two years later. Vulkan's reputation for taking nearly 1000 lines of code just to render a single triangle is no joke! But I was ready for the challenge. Let's dive in and see what's been taking me so long.
 

Early Rumblings

 
August 21, 2023: With no idea what I was doing, I searched "vulkan tutorial", clicked on the first result, and got to work. In a single week of leisurely progress, I already had my first triangle in just 845 lines of code (well, with the help of a 4913-line helper system called volk).

I may have just been copy-pasting tutorial segments together, but it felt like I was on a roll! It wouldn't take much work to add more shapes to the scene. Most of those 845 lines were for setting up the program, like establishing a proper connection with the graphics card, reserving the right types of memory, and other mundane details. Soon enough I had two triangles (aka a rectangle)!
 
By week three, the window could be resized (including full-screen mode!) and my shaders were compiling automatically without external software (don't worry if you don't know what that means). Not long after, I had textures and could even animate the scene!
 
In the past, my games had basically just been lots of shaded textures sliding around, so surely I'd covered most of the features by now. All I had to do was fill in some gaps and incorporate this project into my engine.


The Drought

 
And then the realization gradually dawned on me that I hadn't actually accomplished all that much yet. Vulkan is at its best when, just like in this tutorial demo, you know in advance exactly what your visuals require so you can set every structure in stone. When you do this, your GPU turns into The Sphinx and winks at you.

But if anything in your scene needs to change or behave unpredictably, like running scripts from a file, you are left on your own to solve the riddle of moving the entire Egyptian Pyramids around by hand in a well-coordinated improvisational dance.

I had climbed the first hill only to discover the vast desert ahead.

Welcome to Vulkan.
 

Dormancy

 
For the next five months or so, I was stuck in a loop. When I'd start writing the next critical feature, the app would naturally stop working until I finished that part. During this under-construction phase there'd be nothing to see but boring old C++ code, sometimes for weeks. Then I'd pull the feature together, only to be back to exactly where I was before: the spinning squares.
Always those same spinning squares.







I was really stuck with those spinning squares.
 
Spinning squares.

Sure, I could've changed my test app's facade now and then, but that would have been a distraction from the real goals. Every time I arrived back at this scene (you know, the spinning squares), I knew my code was another step closer to solving Vulkan's puzzles. So you may wonder... how on earth could this process be so dizzying for so long?
 

Inside the Magma Chamber


One of Vulkan's early accomplishments was that it "minimizes driver overhead", meaning it removed much of the work required for people to bring Vk support to your hardware and many other devices. That's exciting! The downside is that this work didn't disappear, but instead became the responsibility of every Vk-based program, like NetMission Engine. And that work... is less exciting.
 
To study the level of detail, we could take a magnifying glass and zoom into pretty much any portion of Vk-based code. How about this moment: our game is running at 60 frames per second, and it just directed a new frame for us to display. How do we show that final image on the screen?
WARNING: This section gets somewhat technical. If you begin to experience symptoms of discomfort, feel free to skip to the next section. I think you'll get the point pretty fast.
In OpenGL we'd use a single built-in function, usually something with a name like SwapBuffers(). And we're done! The graphics driver probably does some interesting stuff under the hood there.
 
But in Vulkan? ...

I spent too many hours making this gif.
... Well first, our image isn't in the right format yet. It's been set up to receive new pixels, not display them, which is an important distinction. To convert the image, we just need to fill out a 12-field VkImageMemoryBarrier2 form and a 9-field VkDependencyInfo form. We'll turn in this paperwork to a vkCmdPipelineBarrier2() which, just like the name doesn't suggest, offers image-reformatting services on the side. Be careful: if we're trying to use this GPU to the fullest, our image might be exclusive to only one "queue family" at a time. You see, it's further possible that rendering and displaying might operate on different "queue families", in which case we'll need to submit forms to two such pipeline barriers (warning: three in the case of non-image data) indicating an ownership transfer. Be sure to indicate the correct order twice or it might not go through.
 
Still here? Ah, sorry to say, we haven't even started. Literally! With Vk we tend to operate in a future realm where none of this is happening yet, even our image's rendering. Which means we now have a similar story for the accumulated past data referenced by that image, like the positions & colors of all our objects. The game was generating that info, but soon the GPU needs to read it. This data's properties can vary for complex reasons, so our strategy depends on which memory parts are "host coherent" or not, and/or if any are split between a "host visible" space and "host invisible" space. If you forget to do this data conversion here... it might actually still work on many devices, leaving you with a mystery for the rest. Good luck!
 
Moving forward, it's time to submit all our frame's commands into the correct queues so the GPU can eventually prepare our image. Alert: This is assuming our command-submission model is robust enough to handle all the above synchronization dependencies efficiently, or else we'll have performance warnings or impossible constraints. With this done, at long last we can use vkQueuePresentKHR() to "present" the image, and we'll attach a note saying to wait for the image to be ready first, since it's probably not yet. Whoops, tragedy strikes! Our hard-earned image might get rejected here if the window recently resized, so we'll have to react accordingly by e.g. creating a new "swap chain". Yeah, you get the idea. I'll gloss over that part. ...

... And we're done!

Critical Overload


When I researched my options in 2023, Vulkan was the winner for what I needed. I was craving that extreme degree of control & reliability in my engine's graphics & performance, and there are good reasons why so many other software projects are also switching to Vk.

That being said... Vulkan is... well, frankly it's just a really bad time. I heard its designers had some pressure to get version 1.0 out the door as soon as possible. I wish they'd been given more time to clean it up before it hit the fan.

I'd love to at least be able to rename all the unclear and misleading terminology... or fix the paradigm behind how resources get deleted... Synchronization is so confusing that virtually every Vk tutorial and program got part of it wrong. At the time of this writing, the Official Vk Validation Layer reports that the Official Vk Spinning Cube Demo has a nasty SYNC-HAZARD-WRITE-AFTER-WRITE error, and I actually don't know which side of that to believe. There's so much complexity.

Every software development story has some amount of toil and frustration, and unfortunately my experience with Vk is defined by much of that. But the internet has enough negativity already, so I'll do my best to focus on the fun parts. Plus it's worth knowing that the designers have been listening to the community and improving Vulkan over time, slowly but surely.

Anyway, this part's boring. Let's speed ahead.

Comedy Break


One day, I thought I'd be funny to grab arbitrary regions of GPU memory and interpret them as pixels on the screen. Tada, looks really cool on my laptop!
An artistic rendition
I left the glitchy effect open for a few minutes while I worked on something else. Then I closed out, and... huh, it was still flickering? Even over other windows? On my desktop wallpaper?! Even after rebooting?!?! Uh oh. Screen was busted.
The solution was to fully power-off my laptop for a week to alleviate the charge buildup. That did the trick. Screen was fixed! So I immediately made it impossible for NME to ever do this again.
Yep. Hahaha. Real funny... Anyway...

Magma Formation


February 1, 2024: I was finally able to send my half-year Vulkan experiment to others, and... *drumroll*... the scene ran smoothly on everyone's machines!
 
I added the tutorial's 3D model to keep it interesting

I had come so far, but to be clear there was one crucial stretch left: actually replacing NetMission's OpenGL code with all this Vulkan stuff. At first it was thrilling to demolish so much of NME's old code and restructure everything, but with an April 1 deadline looming, the pressure was on. Cue the montage music!

In a few frantic short weeks, I'd implemented enough to make a new game. Not quite enough to meet every feature of my old games, but that could come later. With a shiny new Vulkan-powered engine at my fingertips, I was finally ready to...

Hold on a second... That isn't montage music we've been listening to. That's more like... boss music?!

Phantom Bug: Final Form

There was a problem. About every 1 in 200 times I'd open my Vulkan-based engine, it would freeze immediately. Empty screen, no response.

Hmm, okay. "Troid," you say, "That's only 1 in 200 times, and only like a dozen people are going to play your upcoming demo anyway. The bug might never even happen. Come on, you're in a time crunch! Fix it later. Can't you just let the player close the window and try again?"

Oh, if only it were that simple. The engine would not close.

I don't mean that it simply wouldn't respond to the [X] button in the corner of its window. For that, the operating system (Windows) would notice and help close it. No, in this case, not even Task Manager could not kill the process. I began resorting to lesser-known PowerShell commands with administrative privileges to try to stab this thing. The world's sharpest knives would phase through this process like it didn't exist. Yet there it was, still clinging onto its ghostly Process ID...

I'm serious. The engine would not close.

Not even shutting down the computer could successfully close my engine. The shutdown screen would just spin its little animation at me until the end of time. I couldn't even put my computer into sleep mode for some reason. No, the only way to kill this process was to hold down the power button and hard-reset. There was no choice on the matter: I couldn't allow any number of my players to experience this phenomenon!

It was truly a finicky, elusive nightmare. Even if I attached a debugger mid-freeze, or if I had the engine output any text to show what it was doing, the bug would temporarily go into hiding. It was still there, but not in a way I could study.

Things were getting down to the wire, and I was scared. This was a total deal-breaker. What was wrong with my code? After so much effort, would I have to call it quits and revert the next game back to OpenGL?

...

Well, no. I figured it out. There's this function called vkQueueSubmit(). I already knew that I shouldn't overlap more than one vkQueueSubmit() at the same time if they share any parameters. But it turns out my machine's graphics drivers had a mistake: I couldn't overlap these at ALL, even with completely different parameters, or else I'd be haunted by the phantom. That would've been nice to know!

I probably could have waited for the next driver update for this problem to go away, but I couldn't wait. It was an easy fix! In code we use things called "mutexes" (which stands for "mutual exclusion") to avoid such simultaneity woes. So to make sure my vkQueueSubmit() functions never overlap, I merged a handful of parameter-specific mutexes into a single general one and called it a day. Slower? Maybe. Peaceful? Yes.

I was free at last.

The Vulkanic Eruption

Artwork by Team SCU

March 24, 2024: I released a preview of NetMission 5.0 (the new Vulkan version) to Team SCU, showcasing the title screen for our next April Fool's game. Other than some folks having to manually update their graphics drivers, the application ran smoothly. All systems go! Let's make a game!

April 2, 2024: Well, we missed the deadline by a day, but our little Vk-powered game was released to the world. Time to find out if the new tech holds up!

...And right away, there was a visual bug on someone's computer. Luckily that was a false alarm: it wasn't related to NetMission 5 or Vulkan. Basically I made a silly mistake in one of the shaders, which was easy to fix.
Artwork by Team SCU. Well, the left side at least. My apologies to anyone who saw the cursed one at full speed before I patched it.

(If you're curious: I was unaware that in GLSL the modulo operator (%) has "undefined behavior" (e.g. could be different from computer to computer) with negative values (which I was using), while the modulo function (mod()) is defined for both positive and negative values (same on all computers). If I could redesign GLSL, I'd make % the reliable one since it's easier to use, and maybe rename the other to positivemod() or fastmod() or something, for people who know what they're doing. Oh well. History is history. Live and learn.)

The Falling Ash


Anyway, we made it. NetMission was running Vulkan instead of OpenGL. How'd we do?

Excluding 3rd-party modules, NetMission had a net gain of 2,705 lines of code in the first draft. All things considered that isn't all that much. The whole engine is around 23,165 lines today, ignoring whitespace and comments.

My previous post focused on an older phantom bug: images failing to load in extremely rare circumstances due to OpenGL-related problems. And guess what? Vulkan ate that bug for breakfast! My engine was healed.

But one of the draws of Vulkan is its performance gains, and my engine... actually got slower! While it's true that the old NME couldn't have rendered 10,000 animated blades of grass like the new one, I could've implemented that feature back in OpenGL, too. For cases we can actually compare, the Vulkan edition was definitely worse: more stuttering, higher CPU and GPU usage, and a few really obvious slowdowns. We were lucky that our first game with it was a retro pixel-art game so it didn't matter much!

Coupled with the fact that NME no longer ran well on Steam Deck, these results were honestly pretty demoralizing. Was this worth all the effort overall? It was hard to say.

...Well the answer was yes. But it was hard to say that with any confidence. I was sad and tired.

Regrowth


With less-than-stellar results, the story couldn't stop there. I picked myself up and continued to refine my Vulkan back end one detail at a time into the present day.
  • Too many command submissions, "semaphores", "barriers", etc.? Fixed.
  • Doesn't display properly on Steam Deck? Fixed.
  • Code-generated shapes (like shadows) are way too slow? Fixed.
  • Can't run my old NME games due to missing features? Fixed.
  • Obscure bugs and slowdowns all over the place? Fixed.
I make it sound quick and easy, but some of those points were fairly large undertakings. Vulkan's systems are intertwined in complex ways, where if I have a discovery or realization about the tiniest footnote in the specifications, the outward ripple effect from that might eventually have me drawing new logic diagrams and upending half my code for another redesign.
 
It's like working within a landscape of microservices that all hinge on each other in specific ways, or watching how video game speedruns change their entire routes over time due to seemingly tiny discoveries

...Ok, fine, I'll admit that this kind of puzzle solving can be invigorating at times.
 

Aftermath

 
Let's end this with a little Q&A.
 
Is the Vulkan-powered NetMission fast enough yet?
Yep! It has generally caught up or surpassed the former OpenGL-based version now, and I could optimize further if needed. Loading is like 2x faster (possibly for unrelated reasons), my games work on Steam Deck again, and I've thoroughly ironed out so many bugs that my engine has never felt more slick. I'm happy.

Are you done adding Vulkan into NetMission?
No, but it's become low priority until a future game needs more. Someday I'd love to finish adding 3D support, as well as "compute shaders" to boost particle simulations, fluid dynamics, lighting effects, fractals, and so on. I also want to improve my usage of "descriptors," and I should probably switch shader languages from GLSL to "slang". Might be fun to experiment with 2D vector styles or shifting a bit further toward a "retained mode" architecture. The list goes on and on.

Would you recommend that others learn Vulkan?
For most solo devs, no. I'm hoping something like a Vk2.0 would be designed better. OpenGL is still (mostly) available and capable, other new APIs exist, and there are free frameworks out there which wrap multiple graphics APIs into a single interface, not to mention the many well-established game engines that further hide the complexity. All of these alternatives are worth considering first.

On the flip side, if cutting-edge performance is crucial to your project and you have the time and resources to grapple with Vulkan directly, then go for it and good luck. I still maintain that Vk was the right choice for me and NME, and little did I know I was in good company. When I first started, Godot had just finished their 5-year evolution into a monumental 4.0 Vk release, Blender was about to begin their nearly 2-year journey to achieve a well-received Vk release, and the floodgates were opening for many others to make the switch. Even FFmpeg recently began using Vk to speed up certain decoders!
 
Is anything else new in NetMission besides Vulkan support?
Yes, luckily I wasn't stuck working on Vulkan this entire time. I completely revamped how spatial level data works, and I invented a new file format for linking text, cutscenes, voiceovers, and even translations in a natural way. Together these two features make it dramatically easier to build game content at scale, and I'm hoping to give them their own write-ups here down the road.
 
As an additional push toward usability, I granted access to a trusted individual (aka my brother) to use NetMission to build a game. So I've had to document my engine, teach it, watch another person use it, and receive their feedback. That process has definitely helped me transform NME for the better in innumerable little ways. More on that another day as well.

In other news, there's no Windows-specific code left in the engine, so in theory I could compile it for other platforms (Mac, Linux, iOS, Android, Switch, ...) if I had the time (I don't). So that's cool. Looks like I'm crossing off many items from the shortcomings list in my 2023 engine overview!
 

 
Anyway, that's all for now. Thanks for reading, whoever you are! See you in the next post.

Sunday, December 29, 2024

Fixing a Bug the Hard Way

The day was April 2, 2024. Team SCU had just unveiled a new mystery download link for any and all who dare peek inside. The few brave souls who clicked open the executable file were greeted by not one, not two, but ten-thousand blades of grass blowing in the wind...


That's right, my game engine was now on Version 5.0! Woohoo! And following that announcement was of course a playable demo for Team SCU's stealth video game.

So what did the new version mean exactly? It meant I finally decided to increase the number to 5.0!

Oh, and there was a pretty huge change, too. Our story begins eight months prior...

Lost in the Woods

It was an ordinary Wednesday afternoon in Camp Troidia when three hikers journeyed into the woods. "We'll head this way. Just keep walking," said the leader.

Not long had passed before the hikers wondered if they were headed the right direction. Suddenly they heard a sequence of snapping sounds, growing more fierce then stopping with a heavy thud. It was as if a tree had fallen in the forest, and everyone was around to hear it! Yet, within the resulting plume of dust, there was no toppled timber in sight. "Just keep walking," said the leader.

Hours passed, and the party grew concerned. Where were all the birds and ferns that should be here? The hikers turned a corner and stopped with a jolt. There was a vast angular ravine beneath them, and they'd nearly stepped over the edge! But with the blink of an eye, the ravine was gone. The ground was flat as far as they could see. "Just keep walking," said the leader.

As the sun descended into the horizon, the hikers knew they were lost. In the final moments of light, they pulled out their Book of Maps. "That's strange. The cover just says 'of Maps' now. I guess the other word must've rubbed off in my pack." They flipped through the pages trying to find something relevant, but all the important panels had become scrambled and indecipherable.

"Wait, where's my arm?!" By now it was too late. Within seconds the hikers were consumed... by darkness!

When the search party arrived the next day, they found only two bodies. The leader was was nowhere in sight.

"Oh I'm right here," a mysterious voice interjected, startling the two sleeping hikers awake. "We're totally fine. I'm just invisible right now. Once in a blue moon, Troid's engine doesn't load an image properly for some reason, so weird visual artifacts can happen."

Yep. That's annoying. But the occurrence is almost too infrequent to care. Well, almost...

Finding the Trail

Building a new feature into my engine is a huge commitment, often spanning several months to a year, so I must always choose my next steps wisely. But in Summer 2023, there were suddenly too many important paths forward, and no deadlines to point me toward any in particular. I was feeling as lost as those fictional hikers...

So I organized my thoughts into a full summary of my engine, highlighting the good, the bad, and the ugly. The hope was that this outline would make it obvious to me how to proceed. Spoiler: it worked! Let's walk through some of the shortcomings to discover the pattern I saw:

"Making games in NME means mostly just writing code, with minimal support for visual editors."
"It'd be nice to have model animations back, using standard formats instead of my custom system."

It takes a lot of code to make a game scene work, and as the one who writes the code, I become the de facto author of many core aspects of the game. In other words, I'm wearing too many hats! The more hats I can offload to others, the better.

However, I'm very picky about data formats I will support in NME. For one, I never want developers to feel they must pay money for 3rd-party software to get the most out of my engine. This rules out the most popular 2D skeletal animation tools out there like Spline and Spriter Pro.

A sequence of forces and procedural reactions allow these abstract shapes to glide around believably. I think it's some kind of bear's head maybe? Who knows.

If anyone knows of a robust free solution for playing with that kind of data, let me know! For now all these 2D figures will continue to be animated with my code and/or with more hand-drawn frames by the artists. In my head I was pondering the idea of projecting 3D formats into 2D space so that we could leverage programs like Blender to make game assets. Hey, that reminds me of another thing...

"I believe NME has a lot to offer as a 3D engine, but certain modules restrict it to 2D for now."

If I wish to start supporting 3D models in my engine, I might as well go all in! NME isn't too far off from going full 3D, but it would certainly take some time. The biggest barrier would be my own understanding of graphics APIs, as NME 4.4 uses only the most basic OpenGL features possible to achieve its results. (Note: a graphics API is how games display things to the screen, and OpenGL is the one I've always used). Which reminds me of another thing...

"The graphics capabilities are not reaching their full potential. NME runs well on older hardware, but someday I'd like to take better advantage of modern GPU architectures. I'm behind the times."

Over two decades behind to be more specific! Well, in a sense. I'm somewhat ashamed to admit that all my games had been using something called Immediate Mode for everything.

Sorry, I cut some corners on this one...

What is Immediate Mode? Pretend we're in a restaurant. I'm a chef and you're a waiter. The customer just ordered a bowl of rice from their phone, so I call you over to deliver it to them.

Now, I could just scoop the rice into a bowl and hand it to you, but that would be too sophisticated! Instead, I reach into the cooker and start handing over one grain at a time. I've gotten weirdly fast at this, but you'll still need some patience. I don't provide you with a bowl, and I don't even tell you in advance how much rice was ordered, so you first have to guess what size receptacle to use.

If you guess too small, the customer has to receive their order in multiple batches. But guess too large and that oversized bowl could've been used for something else, so go do some dishes! Anyway that's what Immediate Mode is like for your graphics driver. Many grains. Much improvisation.

In my defense, NME's games don't exactly have much data to send, so Immediate Mode can actually make a lot of sense as it's very flexible. The first room of Prime 2D renders 1640 triangles (from 3258 vertices), which might sound like a lot, but nowadays a single "low-detail character" in a typical console game might already have 10,000-40,000 triangles (source).

Unfortunately going beyond OpenGL's Immediate Mode is a daunting task for a hobbyist like me, even if the concepts are simple to use once understood. Poorly-named terms like Vertex Array Objects, Vertex Buffer Objects, and Element Buffer Objects (all different things) can easily scare someone away. Still, there was no excuse to put it off anymore. By procrastinating on this next layer, I was preventing NME from displaying detailed 3D models or tons of particles, not to mention that Immediate Mode isn't even available on mobile devices.

Hey, speaking of other platforms...

"NME is Windows-only. Native support for other platforms (Apple, Linux, web) would be nice."

I've tried to keep NME as cross-platform as possible, so there are only a few key locations in the engine that still require Windows. One of these locations relates to spinning up multiple OpenGL graphics threads, for tasks like loading several images at the same time. OpenGL was never designed for multi-threading, so this aspect required me to read through incomplete documentation of "WGL functions", discover best practices through old or obscure message boards, and do some plain old trial and error. Which reminds me of another thing...

"There are two phantom bugs that are incredibly rare but have been haunting me for years."

One of those bugs... is the one where images don't always load correctly! When tens of thousands of players tried one of NME's games, the bug was bound to show up a few times.

Did I look into it? Absolutely. The problem happens only with images, so I meticulously studied every image-related shared-state access. I experimented with extra command flushes and synchronization guards, but I wasn't able to narrow it down. It's possible I was hitting an obscure behavior of OpenGL context sharing, WGL functions, or maybe just certain drivers or hardware, but still, I couldn't shake the feeling that it was somehow my fault. I had no idea how to tiptoe around it, other than making load times longer by reducing image submissions to a single thread, just to stop this once-in-a-blue-moon phenomenon. I didn't want to do that, and my time was spread thin, so the bug continued to haunt me.

But... given all of the above shortcomings of my engine, and the path I just walked through... there was another way. Another way to make everything better.

I could switch to Vulkan.

Beneath the Crust

Vulkan (Vk for short) is a modern alternative to OpenGL. All the crumbs for this fell into place so neatly. Working backward:

Vulkan was designed with multi-threading in mind, so my phantom bug would surely go away. I would need fewer OS-specific calls to initiate that, so the codebase would be a step closer to being cross-platform (assuming MoltenVK stays strong). I'd be forced out of Immediate Mode and pulled closer to present-day GPU architecture, now with fancy techniques like Compute Shaders available at my fingertips. NME would take a big step toward eventual 3D capabilities, which would also add future potential to connect with many standard game asset formats.

Don't get me wrong: OpenGL is fine. Its latest flavors are still relevant and can handle the above. But my particular old-school use of it finally rang clear in my head as the #1 thing holding my engine back. I had two options: learn more advanced OpenGL features, or switch to a newer API.

It wasn't a decision to make lightly. I'd be dropping support for older hardware, and if Vulkan lost its traction in the coming years I'd have taken a big misstep. It's significantly more fine-grained than OpenGL, but that's exactly the kind of control I wanted. It seemed I was ready for such a challenge. It was time for NetMission to overcome its greatest weakness and join the world of cutting-edge graphics!

Luckily this switch would probably only take me a month or two, right? Everything would be up and running in no time. What could go wrong?

TO BE CONTINUED IN PART 2...

Tuesday, August 1, 2023

NetMission Engine in 2023

If you're familiar with NetMission already, maybe from playing some of the games it powers, or from engaging with Team SCU's community, then you're probably also familiar with how much of a mystery it is. One developer. Unclear intentions. And he disappears a lot. (Sorry about that.)

Let's fix that with a brand new...

Official Overview, 2023 Edition!

 

 

NetMission (NM or NME) is my private engine for making 2D video games. I started it in 2006 and have used it to produce games of my own as well as games with Team SCU. The most well-known of these was unfortunately discontinued, but it certainly influenced what I've built in the engine.

Today, NME has many features. Here's what you can expect to see in its games:

 

Pixel-Artwork Specializations:

  • Parallax can be difficult in low-resolution pixel-art games. NetMission combines the clarity of the pixel grid with the smoothness of subpixel blending for optimal results. Even without parallax, it lets me be fine-grained about exactly how each sprite should appear each frame.
  • Built-in support for SpinTroid, my 2019 pixel-art rotation algorithm with generally better results than the industry standard (RotSprite). SpinTroid can dynamically rotate entire scenes in real-time, as showcased in past games.

 

Special Effects:

Can be made using NME's GPU-accelerated graphics toolset which enables shaders, intermediate rendering, color operations, fully customizable particles, pre-multiplied texture alphas, sRGB gamma correction, and other such technical terms which I can cover someday. Players have appreciated that NME's games run smoothly on low-end hardware without sacrificing visual quality.


Fine-Tuned Controls:

Not discarding input data under stress: a surprisingly rare feature in the wild.

  • Player input is processed correctly even if the framerate were to drop or stutter, guaranteeing a reliably smooth feel.
  • [NEW!] NME now has controller support! Your feedback was heard!
  • [NEW!] Games can connect any device's signals to any player's actions via any possible data constraints, transformations, or grouped dependencies. Whew! In other words, I can now much more easily add spaghetti important configuration options to my games. Things like...
    • Button-mapping screens
    • Local multiplayer (even within one keyboard)
    • Customizable controls per character/nametag/controller/save slot
    • Arbitrary deadzone shapes
    • Accessibility options for motor control disabilities (e.g. tap-to-hold, rapid-fire)
    • And so on

This system took me forever, but I'm glad I finally did it! Of course, making a nice GUI for all of of this would be its own project, but at least the possibilities are now at my fingertips.

I think the jump signal is coming from the fork actually.


Optimized Asset Management: (aka the nerdy stuff)

  • Uses a thread pool to stream game assets in and out of memory as needed without interrupting gameplay.
  • Handles multi-stage loading and cyclic dependencies with ease, verified extensively with math and tests.
  • At game publish time, processes and packs game assets for fast load times and small file sizes.


3D Audio Soundscape: 

Powered by OpenAL-Soft, which features a wide range of real-time processing (reverb, EQ, positional surround-sound, distortion, etc.), enhanced by NME with seamless chaining of different formats (ogg, mp3, opus, etc.) through an easy-to-use code interface. In NME's games I've been able to implement nifty effects like synchronizing gameplay to music as well as placing large numbers of SFX in the environment for emergent sounds (like a swarm of 52 insects each with their own little pitch-shifting buzz).


Spline-Based Animation Systems:

Just kidding. This system and its custom editing tools were NME's greatest achievement 10 years ago, but I decided to cut all support 5 years ago. (What?!) That's a discussion for another post. For now I get by with other methods of animation, but at least the gifs still look kinda cool.


Saving Done Right:

  • [NEW!] The save system is totally revamped! NME now supports flexible game-specific storage formats with automatic versioning, backwards compatibility, and sanitization. Saving & loading is multi-threaded (so no gameplay interruptions) and can even handle system power failures mid-save (so no data corruption).
  • Relatedly, NME provides easy methods to prevent leaking gameplay events across boundaries, even if you were to like, start a cutscene, pause the game, and reset to title screen all in the same frame. If you watch speedruns, you've probably seen people do stuff like that in other games to exploit bizarre glitches!

 

Physics:

Powered by Chipmunk2D and enhanced by NME with automatic polygon decomposition, tunneling prevention, more powerful abstractions, the ability to change structural state within callbacks, and other confusing phrases that I'll have to explain in a more detailed post again. (Especially since Box2D seems to be back on the rise!)


Multilingual Text Support:

Unicode? No problem. NME unifies BMFont and FreeType as one and can wrap text in a column, align it, scale it, rotate it, type it, and otherwise treat it like any other image. Pretty standard stuff, but it's important for this system to be solid.

 

Instant Publish: 

[NEW!] I can now generate sharable game packages at the push of a button! Yes, everyone would expect this from even the most basic of engines out there, but it used to take me many hours to carefully organize all the right game files and gradually coax NME into forming a new demo. The dark ages...


There are many more features, but those are the current highlights in my view.




NetMission also falls short in many ways. Here are some things I hope to improve in the future:

  • The "Net" in "NetMission" was supposed to suggest online play, which is nonexistent so far. (Lol)
  • NME is Windows-only. Native support for other platforms (Apple, Linux, web) would be nice.
  • There's no lookup system for text. All text is typed directly in the game scripts. (Yikes!)
  • Making games in NME means mostly just writing code, with minimal support for visual editors.
  • The graphics capabilities are not reaching their full potential. NME runs well on older hardware, but someday I'd like to take better advantage of modern GPU architectures. I'm behind the times.
  • The GUI-making system is incomplete. I sometimes just roll a new GUI system on the fly. (Bad!)
  • We're missing rich-text features, like stylizing specific words or handling right-to-left scripts.
  • It'd be nice to have model animations back, using standard formats instead of my custom system.
  • There are two phantom bugs that are incredibly rare but have been haunting me for years.
  • I believe NME has a lot to offer as a 3D engine, but certain modules restrict it to 2D for now.

It'd be so awesome to resolve all the above, so I'll try to make it happen!




Lastly, I'd like to discuss the development process so you know what to expect going forward.

Side note: As mentioned, NME is private. If you're excited about making games and want to get started, you should definitely check out the well-established engines out there like Godot, Unity, Unreal, Game Maker, RPG Maker, and so on. NetMission isn't equipped for wider use right now.

Well, what to expect is that things can move pretty slowly. As a professional musician, I don't always have much time to work on NetMission, and that isn't anything new. If I can get in maybe ~3 hours of coding most weeks, then something that a full-time programmer could accomplish in two weeks might take me over half a year.

It might sound like I should recruit help from others to make it go faster, but that would defeat why I work on it. For a number of reasons I could go into, opening NetMission at this stage could quickly hurt my motivation, momentum, and design philosophy. That said, when the time is right, I do hope to make NME available for others to use. One of my dreams is to make fun educational games, and if NetMission itself can be someone else's fun educational experience, too, that would be amazing. It's just not ready for that yet.

For now, I'll scratch my itch of making fun educational content by posting to this blog, and you can get involved in NME by leaving comments and suggestions on what comes next. It will take patience, but I'm treating this site the same as the engine: write a bit when I get a chance, keep the process fun, go all out, and occasionally I'll have something cool to show. I hope you can be on board with that. :)

 



Thank you for reading this far. I'm sure you have questions. Every paragraph and bullet point in this overview could easily be the topic of its own post and beyond, so I certainly have my work cut out for me!

 ~ Troid92

Wednesday, June 7, 2023

Hello, World!

...

It's about time I write something here.

I've had this Blogger subdomain set up since February 2016. "The story of a videogame engine, in the hands of a busy musician." I always got a kick out of the fact that this subtitle was followed immediately by "No posts." Sounds about right.

But despite my busy music career, the lack of posts on this page has been very misleading. In fact, I even continued posting my development stories elsewhere, although the images there didn't survive long. I'd like to bring those essays here, as soon as I figure out how best to treat them in this new context.

 

"Hold on. What exactly is this 'NetMission' you're developing?"

NetMission is my game engine. Kind of like how Microsoft Word is software for making documents, a game engine is software for making videogames. Over the years I've used NetMission to make a handful of games with others, which I'll talk about in other posts.

If it sounds unusual for someone to make their own engine from scratch, you'd be right! Nowadays if you want to make a videogame, you have many delightful engines to choose from, each backed by huge teams of hard-working and talented professionals.

But when I wanted to make an online multiplayer game 17 years ago, those options weren't ready yet. At the time, it somehow made sense for aspiring indie developers to grab a beginner's programming book and go about it the hard way. I had no idea what I was getting myself into, but I've stuck with it ever since!

Anyway, I haven't posted a significant write-up on NetMission in nearly five years, even though I've still been coding up a storm. Part of that is intentional, as I've had several good reasons to keep it under wraps. But things have changed to a degree, I suppose. Lately I've been getting the sense from others and from myself that it's time for me to start writing again, so... let's get started!

 

"What exactly should I look forward to, Troid?"

Good question! I do have a few guidelines for myself:

  • No programming experience should be necessary to follow along with my articles. Even as I dive into advanced technical topics, I want to make them as approachable and entertaining as possible.
  • This site should become the definitive center for everything NetMission, since information about it is currently scattered and/or nonexistent.
  • I should feel free to branch out into loosely related topics as needed. Games can reach into so many aspects of life, and a game engine should understand and support that.
  • I must write at least 1 article per year. I'll try to do more than this, but you'll have to forgive me as I am a very slow writer.

Otherwise, I am not totally sure what direction I'll go in yet. If you're reading this I am definitely open to questions and topic suggestions.

I guess we'll see how it goes!

 ~ Troid92