<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>dev&gt;mode13h</title>
    <description>~ night-time gamedev &amp; geek ~</description>
    <link>https://mode13h.dev/</link>
    <atom:link href="https://mode13h.dev/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sun, 28 Jun 2026 23:18:10 +0000</pubDate>
    <lastBuildDate>Sun, 28 Jun 2026 23:18:10 +0000</lastBuildDate>
    <generator>Jekyll v3.10.0</generator>
    
      <item>
        <title>Is Fixed-Point Still Relevant?</title>
        <description>&lt;p&gt;Over the last six months I’ve been polishing and optimizing &lt;a href=&quot;https://tofuengine.org/&quot;&gt;Tofu Engine&lt;/a&gt;’s software renderer. Yeah, I know… a full and detailed devlog on this topic post is due, but while I’m organizing my thoughts on that, here’s an interesting byproduct the I think we shall talk about. :)&lt;/p&gt;

&lt;p&gt;After quite a bit of rework to the &lt;a href=&quot;https://en.wikipedia.org/wiki/Bit_blit&quot;&gt;blitter&lt;/a&gt; code, the hot-loop part of the routines (namely, the (roto)scaler) have been rewritten as incremental. We start from a source coordinate, add a constant step for each destination pixel, sample the source texture, and move on. You know the drill.&lt;/p&gt;

&lt;p&gt;As a basic arithmetic type I’ve been using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float&lt;/code&gt; since the very beginning, mostly on the assumption that modern CPUs (with their FPUs) and compilers are clever enough to operate on this type with roughly the same performance as integer types.&lt;/p&gt;

&lt;p&gt;But are we that this assumption is correct?&lt;/p&gt;

&lt;p&gt;While iterating through the destination area, every pixel coordinate (in the source texture) is computed as a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float&lt;/code&gt; and then converted to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int&lt;/code&gt; in order to sample the source texture pixel.&lt;/p&gt;

&lt;p&gt;At that point, a few questions naturally appeared. Is the approximation done with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float&lt;/code&gt; precise enough for this use case? Are we introducing unnecessary rounding noise while repeatedly accumulating small increments? How much does the float-to-int conversion cost? And, since we are in an accumulation hot-loop anyway, would a DDA-like approach be preferable?&lt;/p&gt;

&lt;p&gt;I rapidly threw together some simple benchmarks and the results were… surprising. Floating point is, as expected, not the silver bullet we might think it is.&lt;/p&gt;

&lt;p&gt;This led me to write a small utility library to pack the fixed-point functions I needed (yeah, I know that some other nice libraries exists, but you know… the thrill or reinventing the wheel). I chose for a &lt;a href=&quot;https://en.wikipedia.org/wiki/Q_(number_format)&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Q16:16&lt;/code&gt;&lt;/a&gt; format as the default, since the values I’ll be using won’t reasonably exceed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int16_t&lt;/code&gt; range. Having 16 bits of fractional part still gives enough subpixel precision, while keeping the integer part large enough for ordinary work. Addition and subtraction remain integer operations and conversion back to an integer pixel coordinate is basically a bit-shift.&lt;/p&gt;

&lt;p&gt;I won’t be using it everywhere across my codebase, ‘though, especially to replace what naturally lives in floating point. Floating point math is perfectly suited for a lot of higher-level calculations. Also, I would avoid using it where values can easily escape the range above, as the library does not provide saturation or overflow protection. I’m aiming for is more of a hybrid strategy: do the comfortable high-level setup in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;float&lt;/code&gt;, convert stable starting values and increments once, then let fixed point handle the hot inner portion where it actually buys something.&lt;/p&gt;

&lt;p&gt;You can find the library &lt;a href=&quot;https://github.com/MarcoLizza/libfix32&quot;&gt;here&lt;/a&gt;, along with the benchmark results.&lt;/p&gt;

&lt;p&gt;That is all for now. See ya next. :)&lt;/p&gt;
</description>
        <pubDate>Sun, 28 Jun 2026 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/is-fixed-point-still-relevant/</link>
        <guid isPermaLink="true">https://mode13h.dev/is-fixed-point-still-relevant/</guid>
        
        <category>engine</category>
        
        <category>math</category>
        
        <category>optimization</category>
        
        
        <category>tofu-engine</category>
        
        <category>devlog</category>
        
      </item>
    
      <item>
        <title>Garbage Collection</title>
        <description>&lt;p&gt;Recently, I upgraded &lt;a href=&quot;https://www.lua.org/versions.html#5.5&quot;&gt;Lua&lt;/a&gt; from version &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5.4.x&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;5.5.0&lt;/code&gt;. It has been a long-awaited minor release for our beloved embeddable scripting language. While running a few demos (just to make sure everything was behaving correctly) I noticed that, in at least two cases, a significant amount of memory kept accumulating without being released… to the point where the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;boids&lt;/code&gt; demo would freeze in less than a minute.&lt;/p&gt;

&lt;p&gt;A closer inspection revealed that the temporary objects created during the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update()&lt;/code&gt; step were continuously piling up. But why?&lt;/p&gt;

&lt;p&gt;As it turned out, the engine’s &lt;em&gt;continuous&lt;/em&gt; garbage-collection mode was poorly implemented. First of all, it was unnecessarily overcomplicated: there is no real need to track an arbitrary time window just to decide when to trigger a GC step. Moreover, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC_MODE_CONTINUOUS&lt;/code&gt; mode itself was flawed, because the initial implementation did not take into account that executing a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LUA_GCSTEP&lt;/code&gt; roughly every ~15 seconds is not sufficient to keep up with aggressive allocation patterns. Memory is effectively reclaimed only at the end of a full collection cycle, so the backlog could easily grow out of control.&lt;/p&gt;

&lt;p&gt;After some simplification and a fair amount of testing, I came to the conclusion that the &lt;strong&gt;generational&lt;/strong&gt; strategy works well when it is left entirely to the virtual machine, but when finer control is required the &lt;strong&gt;incremental&lt;/strong&gt; garbage collector is once again the better choice. By performing a single collection step at a lower-priority update frequency (for example, one step every four &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update()&lt;/code&gt; calls), memory usage remains stable even when large numbers of short-lived objects and tables are created.&lt;/p&gt;

&lt;p&gt;I also experimented with running the garbage-collection in short “bursts”, instead of single steps. In theory, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LUA_GCSTEP&lt;/code&gt; can be invoked in a loop until it returns a non-zero value, signaling that a full cycle has completed. However, with the &lt;em&gt;generational&lt;/em&gt; collector this loop only terminates when a &lt;em&gt;major collection&lt;/em&gt; is executed. If the GC keeps operating in &lt;em&gt;minor collection&lt;/em&gt; mode, the loop may never end, effectively spinning forever. This means some form of capping is required, for example:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;luaX_gccycle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lua_State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_steps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(;;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max_steps&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max_steps&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;--&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// To be used in generational GC mode&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lua_gc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_GCSTEP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That said, the actual behavior remains configurable (see the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;config.h&lt;/code&gt; file), but the policy of choice is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Lua’s GC is stopped immediately, in order to disable automatic and uncontrolled garbage-collection triggers.&lt;/li&gt;
  &lt;li&gt;The &lt;em&gt;incremental&lt;/em&gt; garbage-collection mode is explicitly selected.&lt;/li&gt;
  &lt;li&gt;A full cycle &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LUA_GCSTEP&lt;/code&gt; (see above) is executed during the low-priority update step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A nice additional feature is that, when compiled with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TOFU_INTERPRETER_GC_MODE&lt;/code&gt; set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GC_MODE_CONTINUOUS&lt;/code&gt;, the game engine automatically checks the state of the garbage collector and performs a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LUA_GCSTEP&lt;/code&gt; only when the GC is stopped. This makes it possible, if needed, to switch back to an “automatic” mode at run time with minimal effort, without the engine continuing to drive the collection explicitly.&lt;/p&gt;

&lt;p&gt;Finally, a useful byproduct of this work has been a refinement of the run-time debug information related to heap usage. The internal period counter was slightly off, and the VM memory usage was not being tracked accurately (nor was it accessible from Lua). These issues have now been cleaned up, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;System.heap()&lt;/code&gt; correctly reports both system and VM memory consumption.&lt;/p&gt;

&lt;p&gt;( I’m also considering to add a graphical overlay to report the current performance information )&lt;/p&gt;

&lt;p&gt;This naturally led to a further consideration: when dealing with time-varying metrics, it is often useful to apply a &lt;a href=&quot;https://en.wikipedia.org/wiki/Moving_average&quot;&gt;moving average&lt;/a&gt;… but which variant should one choose? Let’s explore that in a future post! :)&lt;/p&gt;
</description>
        <pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/garbage-collection/</link>
        <guid isPermaLink="true">https://mode13h.dev/garbage-collection/</guid>
        
        <category>engine</category>
        
        <category>lua</category>
        
        <category>garbage-collector</category>
        
        
        <category>tofu-engine</category>
        
        <category>devlog</category>
        
      </item>
    
      <item>
        <title>Reworked Image Loading</title>
        <description>&lt;p&gt;A crucial concept behind the design of &lt;strong&gt;Tofu Engine&lt;/strong&gt; is the idea of using &lt;em&gt;palettized&lt;/em&gt; graphics. All image assets are PNG images, which are a popular choice for many other engines due to their lossless nature and wide support across graphics tools.&lt;/p&gt;

&lt;p&gt;During the loading process, an image is automatically converted from its original format (e.g. 32-bit ARGB). A reference palette (with a variable size of up to 256 colours) is used, and the  &lt;a href=&quot;https://en.wikipedia.org/wiki/Color_difference&quot;&gt;best matching colour&lt;/a&gt; is computed for each pixel and stored into an 8-bit-per-pixel buffer. The value of each pixel in this buffer is an index to a palette entry (also known as a CLUT, or colour look-up table).&lt;/p&gt;

&lt;p&gt;Sounds simple enough, right? In practice, it’s that simple, and the initial implementation of the engine loading routine was as follows:&lt;/p&gt;

&lt;p&gt;1) Load the PNG image into a 32-bit, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WxH&lt;/code&gt;-sized buffer (A).
2) Allocate an 8-bit-per-pixel buffer B of size WxH.
3) For every pixel in buffer A, find the best matching colour in the palette and store it in buffer B.
4) Free buffer A.&lt;/p&gt;

&lt;p&gt;With the help of some support libraries (namely, &lt;a href=&quot;https://github.com/nothings/stb&quot;&gt;stb&lt;/a&gt;) this was an easy feat. However, there were some issues:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The full ARGB buffer is loaded only to be released almost immediately. This is a wasteful use of the heap that should be avoided.&lt;/li&gt;
  &lt;li&gt;It was also slow. This isn’t something one would notice at first since the assets of a 2D pixel art engine are usually quite small. However, when loading larger images, the conversion wasn’t as fast as one would hope.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The second issue can easily be solved using &lt;a href=&quot;https://en.wikipedia.org/wiki/Memoization&quot;&gt;memoization&lt;/a&gt;: for each ARGB colour, the best matching colour only needs to be found and stored in a hash table once. Subsequent occurrences will skip the lengthy computation and simply use the cached value. For example, loading an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;800x800&lt;/code&gt; image took &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~0.5&lt;/code&gt; seconds; with memoization, this time was reduced to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~0.1&lt;/code&gt; seconds. That’s quite an improvement!&lt;/p&gt;

&lt;p&gt;Solving the first issue, however, is a different matter.&lt;/p&gt;

&lt;p&gt;Ideally, the fastest loading time would be achieved if the original image were already in a palette-based format, as it could be loaded straight into the final buffer without any intermediate processes. However, this would contradict a fundamental design choice we made when designing the game engine: &lt;strong&gt;the reference palette is controlled by the script and shouldn’t be fixed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We can, however, reach a compromise by mean of &lt;strong&gt;progressive loading&lt;/strong&gt; of the PNG image. By loading it row-by-row and converting each scanline on the fly we would require only an additional buffer for the row. To accomplish this we switch to &lt;a href=&quot;https://libspng.org/&quot;&gt;spng&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We adapted the engine code, moving all the image loading routines to an internal module called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;image&lt;/code&gt; and generalising the API to be callback-driven. This allowed us to achieve our objective of not affecting loading times (we are totally on par with the previous “non-progressive” implementation), while using only a fraction of the memory.&lt;/p&gt;

&lt;p&gt;We also added miniz as a library, offering a ZLIB-grade stream compressor that we can use for other features in the future. Also, reworking the API gave us the opportunity to refactor it, making it far more generic and abstract (thanks to the loading callbacks).&lt;/p&gt;

&lt;p&gt;I guess we should be satisfied with our results, as we can’t do any better without failing our design choices.&lt;/p&gt;

&lt;p&gt;Or no? :)&lt;/p&gt;
</description>
        <pubDate>Sun, 21 Sep 2025 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/reworked-image-loading/</link>
        <guid isPermaLink="true">https://mode13h.dev/reworked-image-loading/</guid>
        
        <category>engine</category>
        
        <category>image</category>
        
        <category>optimization</category>
        
        
        <category>tofu-engine</category>
        
        <category>devlog</category>
        
      </item>
    
      <item>
        <title>Multimedia Backend Shenanigans</title>
        <description>&lt;p&gt;When I started working on &lt;strong&gt;Tofu Engine&lt;/strong&gt; (way before its name was decided… and even before I had my first dog who, coincidentally, is also named Tofu) the first decision I made was that it &lt;em&gt;had to be multi-platform&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Beyond more or less debatable personal choices on the technology stack (indeed, it would make sense to write a post describing it a little more in detail, with a nice description of the architecture), in order to make a game-engine work on different platforms (although now, much more than in the past, they significantly resemble each other) one fundamental problem must be solved: how to manage the multimedia compartment in a uniform way.&lt;/p&gt;

&lt;p&gt;Because… well… in layman terms, all a video game down in its core has to do is:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;receive inputs from the user,&lt;/li&gt;
  &lt;li&gt;display images, and&lt;/li&gt;
  &lt;li&gt;play sounds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;( and, of course, another ton of things :D )&lt;/p&gt;

&lt;p&gt;If we were only to code on Windows (or derivative systems, such as the &lt;a href=&quot;https://it.wikipedia.org/wiki/Xbox&quot;&gt;Xbox&lt;/a&gt;), we would natively have at our disposal &lt;a href=&quot;https://en.wikipedia.org/wiki/DirectX&quot;&gt;Direct-X&lt;/a&gt; which, despite its age (it is now almost thirty years old) and above any criticism, absolves these three functions excellently and uniformly. Once you come to terms with DCOM and its idiosyncrasies, there is no need for any additional third-party components, as everything have already been included in the operating system itself since Windows 95-OSR2.&lt;/p&gt;

&lt;p&gt;But, needless to say, it would have been too simple to just support Windows, with its huge market share in gaming. We also want to support Linux&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. And maybe some ARM architecture like the one running Raspberry and Ambernic devices. Or Android devices! And why not &lt;a href=&quot;https://en.wikipedia.org/wiki/WebAssembly&quot;&gt;WebAssembly&lt;/a&gt; to have games our running into a web-browser?&lt;/p&gt;

&lt;p&gt;( yes, for the moment that’s all the support macOS is getting :D )&lt;/p&gt;

&lt;p&gt;Luckily, we do not have to work like hell and write a distinct and different multimedia support for each of the target platforms. There are valid third-party libraries that allow us to relieve ourselves of this task.&lt;/p&gt;

&lt;p&gt;Initially, I chose to rely on &lt;a href=&quot;https://www.sfml-dev.org/&quot;&gt;SFML&lt;/a&gt;. At that early stage, I took it for granted that I wanted to use C++ for writing code, and this library seemed the most appropriate. When I had discarded C++ in favour of C99 (the reason why I did this is a topic for another post) I also moved to &lt;a href=&quot;https://en.wikipedia.org/wiki/Raylib&quot;&gt;Raylib&lt;/a&gt; to have as quick as possible a proof-of-concept of what later became &lt;strong&gt;Tofu Engine&lt;/strong&gt;. A while later, I finally settled to &lt;a href=&quot;https://www.glfw.org/&quot;&gt;GFLW&lt;/a&gt; which is still in use today.&lt;/p&gt;

&lt;p&gt;( If you are curious to read some of the details of this initial phase of development of the &lt;strong&gt;Tofu Engine&lt;/strong&gt;, I suggest you read &lt;a href=&quot;/tofu-engine-3&quot;&gt;this post&lt;/a&gt; ).&lt;/p&gt;

&lt;p&gt;GLFW is an amazing piece of software, and fulfils its task really well… however, over the the past year and a half I have grew increasingly uncomfortable. I began to question my initial choice of using GLFW as I observed that the library support from the authors (and contributors) was becoming increasingly slower and scarce at the point that the latest (minor) update dates more than one year ago. Which is not necessarily an issue when a project is stable and feature complete… but in the case of GLFW there is a conspicuous number of flaws awaiting resolution, and many missing features that I begin to fear will never see the light of day.&lt;/p&gt;

&lt;p&gt;I held on for a long time, fighting my urge to find a solutions to this. Few things are worse that realizing you can’t trust the tech on top of which you have build your game-engine. It’s an obsession of mine to keep libraries always up-to-date so I forced myself to ignore that little voice inside me that kept complaining about it… until one day….&lt;/p&gt;

&lt;p&gt;… on 21 January 2025, after a very long wait, &lt;a href=&quot;https://discourse.libsdl.org/t/announcing-the-sdl-3-official-release/57149&quot;&gt;SDL3&lt;/a&gt; was released.&lt;/p&gt;

&lt;p&gt;I initially had chosen not to use SDL because it seemed a bit (too much?) overabundant in the amount of features (and APIs) offered. I feared to bloat my codebase too much… and a tiny part of me didn’t want to be spoiled that much, as I didn’t want to deprive myself completely of the fun of reinventing the wheel! :D&lt;/p&gt;

&lt;p&gt;( just kidding… sort of… :P )&lt;/p&gt;

&lt;p&gt;Anyhow, SDL3 just seems &lt;em&gt;way too interesting&lt;/em&gt; to be ignored, in particular:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;it is written with full C99 support in mind, thing that not even GLFW does (I’m not proud of this, but I had to resort to a few tweaks to its code to selectively “silence” some of the more pedantic warnings that I personally enable by default and treat as blocking errors);&lt;/li&gt;
  &lt;li&gt;it has a far better gamepad support than ANY OTHER library (especially on Linux). I realised when I was working to the source code of another backend (&lt;a href=&quot;https://github.com/ColleagueRiley/RGFW&quot;&gt;RGFW&lt;/a&gt;) with the idea of extending it. Taking GLFW as a reference, I noticed that the gamepad support on Linux is really very (but very) primitive compared to SDL’s which is Steam-compliant.&lt;/li&gt;
  &lt;li&gt;it has native support for the &lt;a href=&quot;https://github.com/mdqinc/SDL_GameControllerDB&quot;&gt;always-up-to-date database of gamepad definitions&lt;/a&gt;. Also GLFW support it, but only at a very basic level without really taking into account the exceptions represented by special input devices (such as those on consoles);&lt;/li&gt;
  &lt;li&gt;it has full support for &lt;strong&gt;haptic feedback&lt;/strong&gt;, the lack of which &lt;a href=&quot;/back-on-track/&quot;&gt;I have complained about before&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;it is supported by &lt;a href=&quot;https://en.wikipedia.org/wiki/Emscripten&quot;&gt;Emscripten&lt;/a&gt;, which would comfortably open the door to &lt;a href=&quot;https://en.wikipedia.org/wiki/WebAssembly&quot;&gt;WebAssembly&lt;/a&gt; and to browsers support;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, above all, the fact that it is used by a &lt;strong&gt;huge&lt;/strong&gt; number of commercial products makes us safe from the possibility of unexpected flaws and lack of continued and future support.&lt;/p&gt;

&lt;p&gt;So… well, all that’s left to do is to start reworking the innermost part of the game-engine code and perform a delicate surgery. The doubts are still many (how complicated will it be to include and compile the code of SDL3 so as not to have external dependencies? Will it be possible to exclude certain “sub-modules” of the library?)…&lt;/p&gt;

&lt;p&gt;… but it will definitely be a lot of fun. :)&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Actually, I have always considered &lt;strong&gt;of primary importance&lt;/strong&gt; supporting Linux. Nowadays, Linux is a more interesting and stimulating reality from the gaming point of view. Thanks to Valve’s SteamDeck the interest to the idea of &lt;em&gt;Gaming-on-Linux&lt;/em&gt; (for the past three years) has shifted and attracted a lot of attention. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/multimedia-backend-shenanigans/</link>
        <guid isPermaLink="true">https://mode13h.dev/multimedia-backend-shenanigans/</guid>
        
        <category>engine</category>
        
        <category>backend</category>
        
        <category>architecture</category>
        
        
        <category>tofu-engine</category>
        
        <category>devlog</category>
        
      </item>
    
      <item>
        <title>Game Engine Sandboxing</title>
        <description>&lt;p&gt;A game engine is much like an operating systems. Or, better, a (virtual) &lt;em&gt;guest&lt;/em&gt; machine running inside a (physical) &lt;em&gt;host&lt;/em&gt; machine.&lt;/p&gt;

&lt;p&gt;This has been true since pretty much the very beginning of game-development and we could trace even in the ’80s game in which the it’s &lt;em&gt;core&lt;/em&gt; was reusable (and reused) more than once. &lt;a href=&quot;https://en.wikipedia.org/wiki/Z-machine&quot;&gt;Z-Machine&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/SCUMM&quot;&gt;SCUMM&lt;/a&gt; have been a forerunners on the topic (and, personally, one if not the single reason I wanted to learn how to code games in the first place… so, shame on them! :D).&lt;/p&gt;

&lt;p&gt;However, it was with &lt;a href=&quot;https://en.wikipedia.org/wiki/Doom_(1993_video_game)&quot;&gt;DooM&lt;/a&gt; that the concept of a reusable game-engine could be said to have spread on a large scale (in addition to the concept of &lt;a href=&quot;https://en.wikipedia.org/wiki/Doom_modding&quot;&gt;WAD files&lt;/a&gt;, another “passion” of mine in those years).&lt;/p&gt;

&lt;p&gt;With appropriate tools and means, anyone was given the opportunity to modify the basic logic of the game at will and even change it almost radically. In the vast majority of cases, there was a &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-specific_language&quot;&gt;DSL&lt;/a&gt; in the way, suitably constructed to fit like a glove.&lt;/p&gt;

&lt;p&gt;Among the fundamental characteristics of the &lt;em&gt;host&lt;/em&gt; machines of that time was that they were (1) isolated from other computers (we were still a long way from today’s state in which every electronic device is potentially continuously connected to a network) and (2) strictly single-user. Security problems, therefore, were not many… except for a few sporadic computer viruses that caused a sensation, spreading like a cold by exchanging infected disks (I remember the first experiences with &lt;em&gt;boot sector viruses&lt;/em&gt; in the Amiga, like &lt;em&gt;SCA Virus&lt;/em&gt; and &lt;em&gt;Byte Bandit&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;For this reason, all things considered, it is not surprising that for a long time, in the context of game-engines, very few were ever interested in the possible related security problems.&lt;/p&gt;

&lt;p&gt;However, with the advent of &lt;em&gt;general purpose&lt;/em&gt; scripting languages such as &lt;a href=&quot;https://www.lua.org/&quot;&gt;Lua&lt;/a&gt;, a little more care is required: what is known as &lt;strong&gt;sandboxing&lt;/strong&gt; should be implemented, i.e. the idea of providing the user (in this case the programmer) with a controlled environment isolated from the &lt;em&gt;host&lt;/em&gt; so that the integrity of the latter is guaranteed in any case.&lt;/p&gt;

&lt;p&gt;For &lt;a href=&quot;https://tofuengine.org/&quot;&gt;Tofu Engine&lt;/a&gt; this was achieved gradually and naturally.&lt;/p&gt;

&lt;p&gt;The first step concerns an appropriate access management for the file system. To this end, we set about writing an abstraction library which (among other things) completely inhibits the use of absolute &lt;em&gt;paths&lt;/em&gt;. In the case of Lua’s virtual machine, this also meant defining a custom &lt;em&gt;reader&lt;/em&gt; and &lt;em&gt;searcher&lt;/em&gt; (used for the resolution of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require()&lt;/code&gt; instruction). More specifically, we had to redefine the default Lua behaviour:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Lua default searchers are stored as four entries in the `package.searchers` table, as follows:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//   - a searcher that looks for a loader in the `package.preload` table,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//   - a searcher that looks for a loader as a Lua library,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//   - a searcher that looks for a loader as a C library,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//   - a searcher that looks for an all-in-one, combined, loader.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// The function modifies the table by clearing table entries #3 and #4. The first one is kept (to enable module&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// reuse), and the second one is overwritten with the given `searcher`.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// As a result the module loading process is confined to the custom searcher only.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// See: https://www.lua.org/manual/5.4/manual.html#pdf-package.searchers&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;luaX_overridesearchers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lua_State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lua_CFunction&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;searcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_getglobal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;package&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// A ... A -&amp;gt; A ... A T&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_getfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;searchers&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// A ... A T -&amp;gt; A ... A T T&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Move the `searchers` and `package` tables *before* the upvalues so we can &quot;close&quot; them into&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// a function-closure. Then use the closure to override the 2nd searcher (keeping the &quot;preloaded&quot; helper).&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// A ... A T T -&amp;gt; T A ... A T&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;nup&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;// T A ... A T -&amp;gt; T T A ... A&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_pushcclosure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;searcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// T T A ... A -&amp;gt; T T F&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_rawseti&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;// T T F -&amp;gt; T T&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Discard the others (two) searchers.&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_pushnil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_rawseti&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// package.searchers[3] = nil&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_pushnil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_rawseti&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// package.searchers[4] = nil&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;lua_pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Pop the `package` and `searchers` table.&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// Upvalues have already been consumed by `lua_pushcclosure()`. No need to clear the stack.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second fundamental aspect concerns the functions (Lua) leaves available to the programmer. As already mentioned, since Lua is a &lt;em&gt;general-purpose&lt;/em&gt; language, it also makes available APIs that are potentially dangerous (among all those relating to file-system access) and definitely not suitable in the context of a &lt;em&gt;sandboxed&lt;/em&gt; game-engine we long to.&lt;/p&gt;

&lt;p&gt;When implementing the FFI interfacing module (called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LuaX&lt;/code&gt; in the context of my game-engine), I initially simply made a clone of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;luaL_openlibs()&lt;/code&gt; function:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;luaX_openlibs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lua_State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaL_Reg&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;libraries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_GNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_base&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_LOADLIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_COLIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_coroutine&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_TABLIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_table&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if !defined(LUAX_NO_SYSTEM_LIBRARIES)
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// System libraries can be disabled to have a proper &quot;sandbox&quot; environment.&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_IOLIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_io&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_OSLIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_os&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif  &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* LUAX_NO_SYSTEM_LIBRARIES */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_STRLIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_string&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_MATHLIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_math&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_UTF8LIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_utf8&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if defined(DEBUG)
&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// Debug module is loaded only for the `DEBUG` build, of course.&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_DBLIBNAME&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaopen_debug&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif  &lt;/span&gt;&lt;span class=&quot;cm&quot;&gt;/* DEBUG */&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;luaL_Reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;library&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;libraries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;library&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;library&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;luaL_requiref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;library&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;library&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;lua_pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Remove the library (table) from the stack.&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The idea of replicating an existing function, although not optimal, seemed decent to me. In fact, for quite a while I continued to use it without any problems. Or any doubts it would be “enough”.&lt;/p&gt;

&lt;p&gt;Little by little, however, I realised that this approach was not the best possible: while the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;io&lt;/code&gt; library was certainly to be avoided at all costs, parts of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;debug&lt;/code&gt; libraries might guarantee better reuse of existing code. Specifically, I realised this when trying out a &lt;a href=&quot;https://2dengine.com/doc/profile.html&quot;&gt;famous profiling module&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hence the idea to look into the matter. Almost by chance, at some point, I came across the description of how &lt;a href=&quot;https://luau.org/sandbox&quot;&gt;Luau&lt;/a&gt; implements &lt;em&gt;sandboxing&lt;/em&gt;. So, why not take a cue from those who have already made considerations in this regard, not least because of the enormous diffusion of the language itself and its use in a context where security is mandated (i.e. &lt;a href=&quot;https://en.wikipedia.org/wiki/Roblox&quot;&gt;Roblox&lt;/a&gt;)?&lt;/p&gt;

&lt;p&gt;Consequently, instead of making a “personal variant” of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;luaL_openlibs()&lt;/code&gt; function, I opted to directly modify the code of the Lua implementation included in the game-engine, making the following changes:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;io.&lt;/code&gt; library has been removed in its entirety;&lt;/li&gt;
  &lt;li&gt;in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;os.&lt;/code&gt; library the only supported functions are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clock&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;date&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;difftime&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;time&lt;/code&gt;;&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;debug.&lt;/code&gt; library has stripped down almost completely with only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;getinfo&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sethook&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceback&lt;/code&gt; functions available;&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.&lt;/code&gt; library, as well, has been removed trimmed down a bit (in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Luau&lt;/code&gt; it has been removed entirely) leaving only the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require&lt;/code&gt; function and the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;searcher&lt;/code&gt; table-index available;&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dofile&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;loadfile&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;collectgarbage&lt;/code&gt; Lua standard functions have been removed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Unlike in Luau, however, no changes have been made to support for pre-compiled sources (i.e., included in pre-compiled P-code format). These can be included without any problems as generated by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;luac&lt;/code&gt; since the programmer is given “full confidence” to include lawful code within the game he is making.&lt;/p&gt;

&lt;p&gt;Although I don’t particularly like making changes to the libraries I use, it is something I have occasionally found myself having to do in the course of a project (if only to resolve compilation warnings). In principle, therefore, I find this kind of approach tolerable given the (fundamental) objective of having a system as sandboxed as possible.&lt;/p&gt;

&lt;p&gt;After all, the fact that Lua’s codebase changes very rarely helps us in this endeavour. :)&lt;/p&gt;
</description>
        <pubDate>Fri, 28 Feb 2025 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/game-engine-sandboxing</link>
        <guid isPermaLink="true">https://mode13h.dev/game-engine-sandboxing</guid>
        
        <category>engine</category>
        
        <category>lua</category>
        
        <category>embedding</category>
        
        
        <category>tofu-engine</category>
        
        <category>devlog</category>
        
      </item>
    
      <item>
        <title>A Case for Lua Performance</title>
        <description>&lt;p&gt;When using an embedded scripting language in a game-engine (or in any other real-time operating software) one should always take into account &lt;strong&gt;performances&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Even in the case of a JIT interpreter, scripted code more often that not loses when compared to native code (e.g. resulting from compiled C99 code). This is not only due to the fact that &lt;a href=&quot;https://en.wikipedia.org/wiki/P-code_machine&quot;&gt;P-code&lt;/a&gt; can’t be faster than executing machine code, but also because of the different impact the data structure and memory usage have on the CPU.&lt;/p&gt;

&lt;p&gt;As a rule-of-a-thumb, common sense suggest that complex algorithms should be implemented natively. Python, for example, proves this on daily basis with OpenCV: one can dismiss the language as “slow” (which is not, anyway), but the OpenCV library runs as native code and offers near real-time performances.&lt;/p&gt;

&lt;p&gt;There are, however, other cases where it’s a tad more difficult to draw the line between what should be left on scripting side and what should be implemented as natively.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Important notice&lt;/strong&gt;: I’ll be considering only the reference (PUC) Lua 5.4.7 release in the following. Neither &lt;a href=&quot;https://luajit.org/&quot;&gt;Luajit&lt;/a&gt; or &lt;a href=&quot;https://luau.org/&quot;&gt;Luau&lt;/a&gt; will be taken into account.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;a-vector-class&quot;&gt;A vector class&lt;/h2&gt;

&lt;p&gt;Any self-respecting game-engine almost certainly feature an abstraction of the (either 2D or 3D) vector concept. In the case of &lt;strong&gt;Tofu Engine&lt;/strong&gt; this is a strictly a two-dimensional vector, implemented as a class, with an idiomatic form of this type.&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;setmetatable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- Methods will be added here...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Actually, in &lt;strong&gt;Tofu Engine&lt;/strong&gt; there is an easier way to implement a class (i.e. via the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class.lua&lt;/code&gt; module), but the substance does not change.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As a direct consequence every instance of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vector&lt;/code&gt; class will be a Lua table. Let’s just keep this in mind and add some more methods.&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;setmetatable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;magnitude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- Well know Lua tip! Use local variables to save table accesses!&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- Tip! Avoid FFI call to `math.sqrt()`!&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;normalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;magnitude&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;angle_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;math.atan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- More methods would follow here...&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have added only five methods, as they sum up pretty well three method categories of increasing computational impact:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;two methods that perform simple operations using only Lua code (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dot()&lt;/code&gt;),&lt;/li&gt;
  &lt;li&gt;two more complex Lua-code-only methods (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;magnitude&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;normalize()&lt;/code&gt;, exploiting the equivalence &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sqrt(x) == pow(x, 0.5)&lt;/code&gt;),&lt;/li&gt;
  &lt;li&gt;a simple method that relies on an FFI function (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;angle_to()&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Taking a look at the full &lt;a href=&quot;https://github.com/tofuengine/tofu/blob/master/src/kernal/tofu/util/vector.lua&quot;&gt;implementation&lt;/a&gt; straight from the game-engine shows that, in principle, all methods fall into one of these categories.&lt;/p&gt;

&lt;h2 id=&quot;finding-the-costs&quot;&gt;Finding the costs&lt;/h2&gt;

&lt;p&gt;It well known that &lt;em&gt;« premature optimization is the root of all evil »&lt;/em&gt;. We simply can’t proceed and blindly &lt;em&gt;optimize&lt;/em&gt; without proper data.&lt;/p&gt;

&lt;p&gt;A simple (but effective) way evaluate the cost of a piece of code is to run it a given number of times and measure the time it took (also on average, if we are interested in that). In Lua, this can be achieved with a helper function.&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- `closure` (function) :- the function closure we want to profile&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- `tag` (string) :- string identifier used for debug&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- `rounds` (number) :- amount of iterations the function will be evaluated&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;-- `baseline` (number, optional) :- baseline value subtracted from the final result&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;closure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rounds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;baseline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;os.clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rounds&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;closure&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;os.clock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elapsed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baseline&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;string.format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;`%s` took `%.3f` seconds&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elapsed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elapsed&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For example, we will use if as follows.&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ROUNDS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000000&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;vector:add()&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ROUNDS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;One may notice that there’s an additional cost in handling a closure call. However, with a sufficiently big amount of iterations the overhead will be dampened and won’t be that significant. Moreover, as long we profile everything in the same way we are good.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Most importantly, ‘though, we can measure the &lt;em&gt;baseline&lt;/em&gt; of a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nop()&lt;/code&gt; function. This will let us determine the (almost) exact amount of time spent due to the profiling overhead.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;lets-measure&quot;&gt;Let’s measure!&lt;/h2&gt;

&lt;p&gt;Now that we have a convenient way to profile our code, we can apply changes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vector&lt;/code&gt; class and implement &lt;em&gt;natively&lt;/em&gt; some existing methods. We need to mimics in C99 what we are doing in Lua. For example, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vector:add()&lt;/code&gt; method is implemented in Lua as follows:&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which corresponds to the following P-code:&lt;/p&gt;

&lt;div class=&quot;language-dart highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kernal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tofu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;util&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;lua&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;141&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;143&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instructions&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x6187e71872a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;slots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;upvalues&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;locals&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;functions&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;GETFIELD&lt;/span&gt; 	&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;x&quot;&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;GETFIELD&lt;/span&gt; 	&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;x&quot;&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;ADD&lt;/span&gt;      	&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;MMBIN&lt;/span&gt;    	&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__add&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;GETFIELD&lt;/span&gt; 	&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;y&quot;&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;GETFIELD&lt;/span&gt; 	&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;y&quot;&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;ADD&lt;/span&gt;      	&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;MMBIN&lt;/span&gt;    	&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__add&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;SETFIELD&lt;/span&gt; 	&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;y&quot;&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;142&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;SETFIELD&lt;/span&gt; 	&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;x&quot;&lt;/span&gt;
	&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;143&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;RETURN0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and is natively implemented like this:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// I&apos;m adopting a naming convention for the native Lua-exposed functions,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// and in general for the implementation, so bear with me if this seems a&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// bit too verbose. :)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;vector_add_native_2oo_0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lua_State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LUAX_SIGNATURE_BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_SIGNATURE_REQUIRED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LUA_TLOBJECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_SIGNATURE_REQUIRED&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LUA_TLOBJECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LUAX_SIGNATURE_END&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;lua_getfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_getfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_getfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_getfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUAX_NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUAX_NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUAX_NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUAX_NUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;lua_pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;lua_pushnumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_pushnumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;lua_setfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;y&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lua_setfield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LUAX_&lt;/code&gt; macros above are part of a custom-made Lua-to-C bridge module. It should be intuitively clear enough the sense of them, ‘though.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a similar fashion I wrote native implementations for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;magnitude&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dot&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;normalize&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;angle_to&lt;/code&gt; methods. Profiling the methods over &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;10000000&lt;/code&gt; rounds the following results have been obtained:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Method&lt;/th&gt;
      &lt;th&gt;Lua (d)&lt;/th&gt;
      &lt;th&gt;LuaO (d)&lt;/th&gt;
      &lt;th&gt;LuaC (d)&lt;/th&gt;
      &lt;th&gt;Lua (r)&lt;/th&gt;
      &lt;th&gt;LuaO (r)&lt;/th&gt;
      &lt;th&gt;LuaC (r)&lt;/th&gt;
      &lt;th&gt;gF/sF&lt;/th&gt;
      &lt;th&gt;f(x)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;magnitude&lt;/td&gt;
      &lt;td&gt;2.918&lt;/td&gt;
      &lt;td&gt;2.697&lt;/td&gt;
      &lt;td&gt;2.814&lt;/td&gt;
      &lt;td&gt;1.170&lt;/td&gt;
      &lt;td&gt;1.142&lt;/td&gt;
      &lt;td&gt;0.670&lt;/td&gt;
      &lt;td&gt;2&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;add&lt;/td&gt;
      &lt;td&gt;2.336&lt;/td&gt;
      &lt;td&gt;2.038&lt;/td&gt;
      &lt;td&gt;5.375&lt;/td&gt;
      &lt;td&gt;0.738&lt;/td&gt;
      &lt;td&gt;0.741&lt;/td&gt;
      &lt;td&gt;1.343&lt;/td&gt;
      &lt;td&gt;6&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;dot&lt;/td&gt;
      &lt;td&gt;1.863&lt;/td&gt;
      &lt;td&gt;1.792&lt;/td&gt;
      &lt;td&gt;4.340&lt;/td&gt;
      &lt;td&gt;0.621&lt;/td&gt;
      &lt;td&gt;0.631&lt;/td&gt;
      &lt;td&gt;1.043&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;0&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;normalize&lt;/td&gt;
      &lt;td&gt;5.930&lt;/td&gt;
      &lt;td&gt;5.710&lt;/td&gt;
      &lt;td&gt;4.523&lt;/td&gt;
      &lt;td&gt;1.959&lt;/td&gt;
      &lt;td&gt;1.874&lt;/td&gt;
      &lt;td&gt;1.023&lt;/td&gt;
      &lt;td&gt;2+2&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;angle_to&lt;/td&gt;
      &lt;td&gt;3.415&lt;/td&gt;
      &lt;td&gt;3.124&lt;/td&gt;
      &lt;td&gt;4.539&lt;/td&gt;
      &lt;td&gt;1.676&lt;/td&gt;
      &lt;td&gt;1.193&lt;/td&gt;
      &lt;td&gt;1.345&lt;/td&gt;
      &lt;td&gt;4&lt;/td&gt;
      &lt;td&gt;1&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;In the table above, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Lua&lt;/code&gt; refers to the plain Lua &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Vector&lt;/code&gt; implementation, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LuaC&lt;/code&gt; to the one with the methods above implemented in native code. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LuaO&lt;/code&gt; indicates a &lt;em&gt;slightly optimized Lua implementation&lt;/em&gt; where&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;library functions are cached/accessed through local references (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;math.atan()&lt;/code&gt; assigned locally as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;local atan = math.atan&lt;/code&gt;), and&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;math.sqrt(x)&lt;/code&gt; have been replaced with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;x ^ 0.5&lt;/code&gt; to save a FFI boundary function-call (in favor of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;POWK&lt;/code&gt; P-code instruction).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Within parentheses the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;d&lt;/code&gt; indicates the &lt;strong&gt;DEBUG&lt;/strong&gt; build (with additional signature checks in the C99 methods), and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt; the &lt;strong&gt;RELEASE&lt;/strong&gt; one (with full compiler optimizations are enabled).&lt;/p&gt;

&lt;p&gt;In the last two columns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gF/sF&lt;/code&gt; reports the amount of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lua_getfield()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lua_setfield()&lt;/code&gt; call required, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f(x)&lt;/code&gt; the number of external function calls (such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sqrt()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;atan2()&lt;/code&gt;) present.&lt;/p&gt;

&lt;p&gt;As a final notice, results are stripped of the baseline overhead: this is crucial for a better analysis.&lt;/p&gt;

&lt;h2 id=&quot;can-we-do-better&quot;&gt;Can we do better?&lt;/h2&gt;

&lt;p&gt;Yes, of course! We can implement the whole vector class as a native UDT (and leave to Lua only some minor &lt;em&gt;embellishment&lt;/em&gt; methods).&lt;/p&gt;

&lt;p&gt;The results are astonishing when compared to the (optimized) Lua implementation.&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Method&lt;/th&gt;
      &lt;th&gt;LuaO (d)&lt;/th&gt;
      &lt;th&gt;C99 (d)&lt;/th&gt;
      &lt;th&gt;LuaO (r)&lt;/th&gt;
      &lt;th&gt;C99 (r)&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;new&lt;/td&gt;
      &lt;td&gt;20.419&lt;/td&gt;
      &lt;td&gt;4.223&lt;/td&gt;
      &lt;td&gt;7.501&lt;/td&gt;
      &lt;td&gt;2.239&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;magnitude&lt;/td&gt;
      &lt;td&gt;2.697&lt;/td&gt;
      &lt;td&gt;1.081&lt;/td&gt;
      &lt;td&gt;1.142&lt;/td&gt;
      &lt;td&gt;0.168&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;add&lt;/td&gt;
      &lt;td&gt;2.038&lt;/td&gt;
      &lt;td&gt;1.773&lt;/td&gt;
      &lt;td&gt;0.741&lt;/td&gt;
      &lt;td&gt;0.215&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;dot&lt;/td&gt;
      &lt;td&gt;1.792&lt;/td&gt;
      &lt;td&gt;1.738&lt;/td&gt;
      &lt;td&gt;0.631&lt;/td&gt;
      &lt;td&gt;0.253&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;normalize&lt;/td&gt;
      &lt;td&gt;5.710&lt;/td&gt;
      &lt;td&gt;2.074&lt;/td&gt;
      &lt;td&gt;1.874&lt;/td&gt;
      &lt;td&gt;0.270&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;angle_to&lt;/td&gt;
      &lt;td&gt;3.124&lt;/td&gt;
      &lt;td&gt;1.707&lt;/td&gt;
      &lt;td&gt;1.193&lt;/td&gt;
      &lt;td&gt;0.264&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Even the vector object creation is (way) faster in the full-native C99 implementation, which is coherent with the fact that it vector class is not modelled with a Lua table.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This reminds us that the creation of an object is expensive (in general), and Lua makes no exception. It is advisable to &lt;strong&gt;recycle and reuse&lt;/strong&gt; instances as much as possible when they are no longer needed, rather than always creating new ones. This concept is called &lt;a href=&quot;https://en.wikipedia.org/wiki/Object_pool_pattern&quot;&gt;object pooling&lt;/a&gt; and is one of the cornerstones in optimizing &lt;em&gt;realtime&lt;/em&gt; systems (such as a video game).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Basing on the results above, we can draw some final observations:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Compiler optimizations do matter&lt;/strong&gt; – as expected, the release build is significantly faster than the debug one, running on average almost twice as fast.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Optimize you Lua code&lt;/strong&gt; – the Lua code runs marginally faster with the above optimization changes, and they are worth be taken into account.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Plain Lua wins&lt;/strong&gt; – in all cases except one the Lua implementation isn’t the worst performing one, both in the debug ang release builds (with only two exceptional cases).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Accessing tables is a bottleneck&lt;/strong&gt; – this is not a surprise, but the major setback when implementing the methods in native C99 code is that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lua_getfield()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lua_setfield()&lt;/code&gt; calls (used to access the vector data, implemented as a Lua table) significantly impacts performances. At the same time, the Lua VM does an &lt;em&gt;amazing&lt;/em&gt; job in accessing tables, and the plain Lua implementation as no such issue. This is evident by comparing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;add()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dot()&lt;/code&gt; methods, with the C99 code significantly slower as the to field access calls grow (way more than the plain Lua code).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Calling functions cost&lt;/strong&gt; – Methods requiring complex mathematical functions have inherent performance penalties, and this is clear by comparing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dot()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;magnitude()&lt;/code&gt; methods (identical, minus &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sqrt()&lt;/code&gt; call).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;epilogue&quot;&gt;Epilogue&lt;/h2&gt;

&lt;p&gt;This concludes our brief (but hopefully interesting) journey into the world of optimization as it relates to the implementation of a pseudo-native UDT.&lt;/p&gt;

&lt;p&gt;It was an opportunity to look in a little more detail at some aspects of Lua’s FFI API, and in particular to understand that some operations can hide unexpected complexities that impact performance. As is often the case, then, the choice of how to model a data type significantly affects the final performance.&lt;/p&gt;

&lt;p&gt;Before leaving, however, we can take a chance to answer a final question: « How do I decide whether to keep an algorithm implementation in Lua or convert it to a native implementation? »&lt;/p&gt;

&lt;p&gt;Essentially we can base our decision it in three points:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;if the data structures are Lua-native, e.g. with extensive use of tables, it is better to stay within the Lua code (since table access via FFI is intrinsically slow). The performance gain offered by selective implementation of native methods is (on average) not significant enough to motivate the additional complexity.&lt;/li&gt;
  &lt;li&gt;if one still wants (or needs) to make a call to a native function, don’t pass tables as formal arguments &lt;strong&gt;but&lt;/strong&gt; unpack the values as separate arguments for the native call.&lt;/li&gt;
  &lt;li&gt;if performance is an absolute priority, implementing the entire class in native code (or at least the most significant portion of the UDT) is a mandatory requirement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s all for now. See ya next. :)&lt;/p&gt;
</description>
        <pubDate>Sat, 14 Dec 2024 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/a-case-for-lua-performance/</link>
        <guid isPermaLink="true">https://mode13h.dev/a-case-for-lua-performance/</guid>
        
        <category>lua</category>
        
        <category>optimization</category>
        
        <category>embedding</category>
        
        
        <category>rants</category>
        
      </item>
    
      <item>
        <title>Going Mobile</title>
        <description>&lt;p&gt;The other day I came across the &lt;a href=&quot;https://anbernic.com/en-it/products/rg35xx-plus&quot;&gt;Anbernic RG35XX+&lt;/a&gt;, which I have to admit I had never heard of before (I’m not really into retro gaming, to be honest).&lt;/p&gt;

&lt;p&gt;I’ve always been curious about mobile gaming… and I’m not talking about the kind that’s all the rage these days with the ubiquitous use of smartphones. I’m talking about the old-fashioned kind, where the gamer picks up a real console with the sole purpose of entertaining him/her.&lt;/p&gt;

&lt;p&gt;The machine has more than its fair share of features: a quad-core 1.5GHz ARM 64-bit CPU, paired with an OpenGL/ES capable dual-core GPU, running on a 3.5-inch 640x480 display. Directional pad, buttons, and a Linux-derived operating system complete the picture.&lt;/p&gt;

&lt;p&gt;What if I want to run Tofu Engine on it?&lt;/p&gt;

&lt;p&gt;Oh… I need to buy one of those thingamabobs, first… and done! While waiting for it to arrive, I can tackle the first aspect: cross-compile to ARM.&lt;/p&gt;

&lt;p&gt;From the beginning, I worked with the idea that Linux should be the one and only development/build environment for &lt;strong&gt;Tofu Engine&lt;/strong&gt;. With little or no effort (thanks to &lt;em&gt;GCC&lt;/em&gt; and &lt;em&gt;MinGW&lt;/em&gt;) I managed to get both the &lt;em&gt;Linux&lt;/em&gt; and &lt;em&gt;Windows&lt;/em&gt; builds on the same development machine (or docker container). I have also tested the (interactive) build on a &lt;em&gt;Raspberry Pi&lt;/em&gt; device and it executes flawlessly; it required a &lt;em&gt;Pi4&lt;/em&gt; device for this purpose, however.&lt;/p&gt;

&lt;p&gt;I was aware that GCC is more than capable of cross-compiling to ARM. All that was needed was the “recipe” to make it work. In a word, &lt;strong&gt;multiarch&lt;/strong&gt;. Taking advantage of this feature, I installed the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;arm64&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;armhf&lt;/code&gt; (for the 64-bit and 32-bit ARM builds respectively) library dependencies and build tools… and with a bit of Makefile-fu… ta-da!&lt;/p&gt;

&lt;p&gt;This also proved to be a good opportunity to reorganise the Makefile and unify the Raspberry Pi build with the RG55XX one (as they are both ARM based)… and lo and behold, it works on both Raspberry Pi 4 and 5! :D&lt;/p&gt;

&lt;p&gt;Having reached this point, however, another problem becomes apparent to me: would the currently used OpenGL version (which is fixed at version 2.1 for simplicity’s sake) work on the RG35XX+ w/ GarlicOS.&lt;/p&gt;

&lt;p&gt;According to the specifications of the &lt;a href=&quot;https://www.allwinnertech.com/uploads/pdf/2021070513595227.pdf&quot;&gt;Allwinner H700 chipset&lt;/a&gt; (the beating heart of the RG35XX+), the &lt;a href=&quot;https://developer.arm.com/Processors/Mali-G31&quot;&gt;ARM Mali G31 GPU&lt;/a&gt; supports OpenGL ES 3.2 (and Vulkan 1.1, but I will not &lt;em&gt;even&lt;/em&gt; explore this unknown territory for the moment).&lt;/p&gt;

&lt;p&gt;I admit that the difference between OpenGL and OpenGL/ES is only clear to me from a conceptual point of view, so my current goal is to study the two variants closely and (hopefully) find a common point of contact.&lt;/p&gt;

&lt;p&gt;It is also an opportunity to review and improve the integration with OpenGL in general, in anticipation of a (possible) future move to more intensive use of the GPU.&lt;/p&gt;

&lt;p&gt;See you soon. :)&lt;/p&gt;
</description>
        <pubDate>Fri, 12 Apr 2024 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/going-mobile/</link>
        <guid isPermaLink="true">https://mode13h.dev/going-mobile/</guid>
        
        <category>platforms</category>
        
        
        <category>tofu-engine</category>
        
        <category>devlog</category>
        
      </item>
    
      <item>
        <title>Back on Track</title>
        <description>&lt;p&gt;The end of the year is just around the corner…&lt;/p&gt;

&lt;p&gt;… and we are actually a little behind on devlogs. Once again. As usual.&lt;/p&gt;

&lt;p&gt;I wish I could say that I’ve neglected the blog because I’ve been concentrating so much on &lt;strong&gt;Tofu Engine&lt;/strong&gt; that I couldn’t find the time to do it, but the harsh reality is different. That is, I have had other projects/commitments that sucked up my time and energy.&lt;/p&gt;

&lt;p&gt;Nevertheless, I can see a glimmer of light on the horizon, having hopes (as well as a very strong urge and determination) to be able to devote some time and get my &lt;em&gt;game engine&lt;/em&gt; back on track.&lt;/p&gt;

&lt;p&gt;In the past days I resumed working on it. Not with the lengthy full-night sessions I was accustomed with, but it’s still something.&lt;/p&gt;

&lt;p&gt;I tackled down what I do periodically to “jumpstart” my activities on the project, that is I have updated the engine’s &lt;em&gt;dependencies&lt;/em&gt;. As I have said and reiterated several times, &lt;strong&gt;Tofu Engine&lt;/strong&gt; was born with the idea of having (almost) no &lt;em&gt;run-time&lt;/em&gt; dependencies. However, it does use other libraries (and it should) which I take care to keep as up-to-date as possible. In fact, if there’s one thing I can’t stand, it’s projects where dependencies are neglected… not keeping them up-to-date, in the long run, can cause quite a few problems. Please, fellows developers, keep your dependencies up to date! =D&lt;/p&gt;

&lt;p&gt;I also took the opportunity to ponder on whether the libraries I had chosen at the time are still the ideal option. I must say that, in principle, I would make the same choice again even today. I do, however, want to make a few remarks on some of them.&lt;/p&gt;

&lt;p&gt;For a short time, I feared that &lt;a href=&quot;https://www.glfw.org/&quot;&gt;GLFW&lt;/a&gt; was about to fade away as a project. From both the website and the main channels, there were no updates and development seemed to be halted. A few pull-requests from contributors were crowding in, but without being integrated into the main code. Thankfully, however, the situation now seems to have improved and work is continuing (I must say also consistently, because it is rapidly approaching the long-awaited new release). In any case, for use in the game-engine what is now possible remains more than sufficient (with the exception of the input source management part, where I would particularly like to see support for &lt;em&gt;force-feedback&lt;/em&gt; and &lt;em&gt;gamepad rumble&lt;/em&gt; integrated).&lt;/p&gt;

&lt;p&gt;In a similar vein, &lt;a href=&quot;https://chipmunk-physics.net/&quot;&gt;Chipmunk2D&lt;/a&gt; is in doubt as to whether or not to maintain it in the long term. Developments are at a standstill, considering that the library is stable and well established. However, &lt;a href=&quot;https://github.com/erincatto&quot;&gt;Eric Catto&lt;/a&gt;, author of &lt;a href=&quot;https://box2d.org/&quot;&gt;box2d&lt;/a&gt;, has been working for some time on &lt;a href=&quot;https://github.com/erincatto/box2c&quot;&gt;a C99-compliant version&lt;/a&gt; of his famous middleware (which is currently written in C++). I plan to try to integrate it very soon.&lt;/p&gt;

&lt;p&gt;Other than that, the first and most immediate objective will be to make the product (finally?) usable by the community. The official documentation absolutely must be completed (in many ways… from technical description, to examples/tutorials, to API documentation)! :P To this end, I intend to elaborate a bit on the project “presentation” so as to make request (veiled or not) for help from external contributors.&lt;/p&gt;

&lt;p&gt;Obviously, then, there are features to be added (quite a few) that I have been taking notes on over the past few months… and others that could potentially be refined, simplified or even (why not) eliminated because they are overabundant.&lt;/p&gt;

&lt;p&gt;On the sidelines, I want to revisit some of the more intimate details of the engine. Without radically revamping the API (hopefully without modifying it in any way) I intend to rework the rendering sub-system, in order to optimize it and make it more sensitive toward power consumption.&lt;/p&gt;

&lt;p&gt;In short, there is a lot of work to be done. :D&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;
</description>
        <pubDate>Thu, 21 Dec 2023 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/back-on-track/</link>
        <guid isPermaLink="true">https://mode13h.dev/back-on-track/</guid>
        
        <category>libraries</category>
        
        
        <category>tofu-engine</category>
        
        <category>devlog</category>
        
      </item>
    
      <item>
        <title>Function Arguments Passing</title>
        <description>&lt;p&gt;Picture yourself working at your desk, tinkering on the design of some of the internals of your game engine (as I wrote in the &lt;a href=&quot;/tofu-engine-v_0_13_0&quot;&gt;previous&lt;/a&gt; devlog post), toward a significant redesign of the game-engine core.&lt;/p&gt;

&lt;p&gt;That’s a lot of work, and you should try and focus as much as possible and limit yourself to what’s strictly related to what’s required.&lt;/p&gt;

&lt;p&gt;But, alas, you already know from the very beginning that’s not going to happen and you’ll find some other interesting topic to let your mind wander about…&lt;/p&gt;

&lt;p&gt;… and, of course, this time I’m making no exception to this by tinkering about &lt;em&gt;arguments passing&lt;/em&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-current-way&quot;&gt;The Current Way&lt;/h2&gt;

&lt;p&gt;Since its inception, I invested a significant portion of time in making the game-engine scripting core &lt;em&gt;efficient&lt;/em&gt;, &lt;em&gt;elegant&lt;/em&gt; and &lt;em&gt;clear&lt;/em&gt; to use. One feature I sought to implement it’s a reasonably performant &lt;em&gt;function overloading&lt;/em&gt; as it was something I liked a lot in &lt;a href=&quot;https://wren.io/method-calls.html#signature&quot;&gt;Wren&lt;/a&gt;, which I was using when I was developing &lt;strong&gt;Tofu Engine&lt;/strong&gt;. Lua doesn’t support overloading straight out-of-the-box (as in C++ or Java, for example) but can be implemented with some minor effort by leveraging the fact that arguments can be optional (they are set to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nil&lt;/code&gt; when missing from the actual arguments list).&lt;/p&gt;

&lt;p&gt;Let’s see and basic example and write a hypothetical function in Lua that writes some text on screen leveraging another (internal and low-level) function:&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_default_color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actual_color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_default_color&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- This is the Lua idiomatic for the C ternary operator.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_draw_text_internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actual_color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We are using the “missing arguments are nil” feature to handle the case when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;color&lt;/code&gt; is not provided… but we can achieve the same result using &lt;em&gt;overloading by arity&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_default_color&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_draw_text_internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actual_color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;elseif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;_draw_text_internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this case, we are differentiating the behaviour by checking the number of actual arguments (i.e. the function arity). It might appear to be more “redundant” and less clever as an approach but, in fact, is much more manageable in the long run as the resulting code is less convoluted and easier to read.&lt;/p&gt;

&lt;p&gt;There are occasions, however, when we just can’t limit ourselves to using the arity to obtain different/specific behaviours, but we need to take into account also the type of the arguments. Let’s refer to this as &lt;em&gt;overloading by type&lt;/em&gt;. An example of this is if we want to write a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vec2:add(...)&lt;/code&gt; method that adds both a vector or a scalar to another vector. Since we have the same amount of arguments in the signature arity is not a sufficient discriminator, so we need to check the type of the actual argument to perform the correct operation:&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;vec2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_or_scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vector_or_scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;number&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vec2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_or_scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_or_scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vec2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_or_scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector_or_scalar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We could go even further and combine both approaches (I’ll leave that as an example for the reader :-P) making things more and more complex (and hairier).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’m not suggesting that function overloading is the suggested way to write code. Quite the contrary, I’m an advocate of “descriptive code”. I favour using clear and explicit names for functions/methods, describing explicitly what they do rather than leveraging intuition. For example, I’d rather write separate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vec2:add_scalar()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vec2:add_vector()&lt;/code&gt; methods, as they don’t require that additional boilerplate “dispatching” code which hinders performances (when we are using interpreted languages, as in compiled languages the overloading is resolved at compile-time) and artificially increases the code complexity. However, there are occasions where a well thought and placed overloaded function/method makes the code &lt;em&gt;better&lt;/em&gt; (see, for example, the first example).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One thing I’m proud of is the relatively simple but clever and efficient way I implemented overloading-by-arity in &lt;strong&gt;Tofu Engine&lt;/strong&gt;, with straight Lua C FFI API. With a sprinkle of ATL-inspired (who remembers it’s way to define and implement window-messages handling?) macro usage, the specific sub-function dispatch is called according to the actual number of arguments.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Overloaded constructor for the `Bank` object. Dispatch is based upon&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// only on the number of actual arguments.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// See `src/modules/bank.c`.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bank_new_v_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lua_State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_ARITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bank_new_1o_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_ARITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bank_new_2os_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_ARITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bank_new_3onn_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_END&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;An extension to this is the implementation of overloading-by-type.&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Overloaded constructor for the `Font` object. We are using a combination of&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// the amount of actual arguments and their types. Please not how the type-based&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// overloading check is done first, as the same arity-based check would trap it&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// erroneously.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// See `src/modules/font.c`.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;font_new_v_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lua_State&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_BEGIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_ARITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;font_new_3osS_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_SIGNATURE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;font_new_4onnS_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_TOBJECT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_TNUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;LUA_TNUMBER&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_ARITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;font_new_3osS_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_ARITY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;font_new_4onnS_1o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;LUAX_OVERLOAD_END&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By having a look on how &lt;a href=&quot;https://github.com/tofuengine/tofu/blob/6a52389e578c53fc5695e97b9913508b03c27ea4/src/libs/luax.h#L98&quot;&gt;overloading is implemented&lt;/a&gt; one can guess that this second approach is slower than the first. This is correct, as the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LUAX_OVERLOAD_SIGNATURE&lt;/code&gt; check is far more complex than &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LUAX_OVERLOAD_ARITY&lt;/code&gt;. Anyhow, when used in seldom-called functions/methods (like, for example, object constructors), this can give some benefits without significantly impacting the overall performance.&lt;/p&gt;

&lt;h2 id=&quot;a-third-way&quot;&gt;A Third Way?&lt;/h2&gt;

&lt;p&gt;It seems like we are acceptably satisfied with the results, so far. Why should we search for another way?&lt;/p&gt;

&lt;p&gt;Well… because there can be cases where both arity- and type-based overloading are not enough. That’s the case, for example, when we have two different overloads of the same function with the same signature.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Back to the disclaimer I made above, I don’t think we should necessarily insist on overloading at this point. Probably a separate, specific, method/function would be preferable. However, we are mostly speculating here… and it’s always worth doing it! :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I’m not particularly fond of Python but I like it’s &lt;em&gt;name arguments&lt;/em&gt; feature. Arguments can be optional, too, and this opens the road to some quality seamless code… for example in Python’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;requests&lt;/code&gt; module: when transmitting data we don’t have separate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post_json()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post_bytes&lt;/code&gt; methods, but a single &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;post(json=None, bytes=None)&lt;/code&gt; that applied a distinct behaviour according to the actual provided (named) arguments.&lt;/p&gt;

&lt;p&gt;Is something like this possible in Lua?&lt;/p&gt;

&lt;p&gt;Well… sort of. We &lt;em&gt;just&lt;/em&gt; need to use &lt;em&gt;*tables as arguments&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The idea is as simple as the name implies: we move the arguments’ whole list and pack it into a table. Then we pass it as the sole argument for the function/method call.&lt;/p&gt;

&lt;p&gt;Easy peasy! :)&lt;/p&gt;

&lt;p&gt;Let’s see a basic example, by rewriting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw_text()&lt;/code&gt; function above mentioned&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_draw_text_internal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;color&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_default_color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which we would call as follows&lt;/p&gt;

&lt;div class=&quot;language-lua highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;draw_text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello, World!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s definitely not rocket science, and it doesn’t seem like a huge improvement, but it’s an approach that gives a more clear and more open approach to extendibility. We can add new arguments and use them to discriminate the function behaviour accordingly, even when they are of the same type, just like in Python thanks to the named arguments feature. Also, we don’t have to stick to a rigid argument order and – overall – the code is more self-documenting. Moreover, unless we did otherwise on purpose, API backward compatibility is easier to implement.&lt;/p&gt;

&lt;p&gt;That’s an interesting bunch of &lt;strong&gt;silver linings&lt;/strong&gt;. Are there any &lt;strong&gt;black clouds&lt;/strong&gt;? Yes, of course, and unfortunately they are pretty annoying!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;First and foremost&lt;/em&gt;, the inner implementation of the functions/methods can quickly become intricate. We need to test the size of the table, the presence of some fields, and maybe their type (in a similar fashion as we did in the initial arity/type overloading examples). It’s not something that can be easily generalized and needs to be tailored to the case in order not to write dull/unoptimized code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Secondly&lt;/em&gt;, tables are to be carefully used in Lua. They are the core of the language, deeply optimized in their usage and made as performant as possible… but they waste resources, nonetheless. When used as arguments they can hinder performance &lt;em&gt;a lot&lt;/em&gt;. Access times for the table fields tend to be slower (albeit optimizable in plain C code with the FFI API), and creating anonymous tables for each call is expensive (both in space and in time).&lt;/p&gt;

&lt;p&gt;For these reasons, they would end in causing bad performances if not properly used.&lt;/p&gt;

&lt;h2 id=&quot;the-verdict&quot;&gt;The Verdict&lt;/h2&gt;

&lt;p&gt;As usual, there’s no silver bullet. However, we can make some considerations and decide accordingly.&lt;/p&gt;

&lt;p&gt;Since we are in the context of a game-engine, our top priority is not wasting resources (mostly CPU but not only) and having as good performance as possible.&lt;/p&gt;

&lt;p&gt;I would relegate table-based overloading to less frequently used calls (e.g. class constructors)… but I like consistency while coding, so I would either move &lt;em&gt;all&lt;/em&gt; my code to this approach or ditch it for good, despite being more versatile.&lt;/p&gt;

&lt;p&gt;All being said, even an eight arguments long signature is not that bad when the codebase reaches maturity and you have a well-documented API! ;-)&lt;/p&gt;

&lt;p&gt;( note for my future self: please commit yourself to ending the engine API documentation :-P )&lt;/p&gt;
</description>
        <pubDate>Fri, 15 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/function-arguments-passing/</link>
        <guid isPermaLink="true">https://mode13h.dev/function-arguments-passing/</guid>
        
        <category>lua</category>
        
        <category>design</category>
        
        
        <category>tofu-engine</category>
        
        <category>lua</category>
        
      </item>
    
      <item>
        <title>tofu-engine v0.13.0</title>
        <description>&lt;p&gt;Hooray!&lt;/p&gt;

&lt;p&gt;An exciting new release of &lt;a href=&quot;https://tofuengine.org/&quot;&gt;&lt;strong&gt;Tofu Engine&lt;/strong&gt;&lt;/a&gt; is now available! You can find the engine code &lt;a href=&quot;https://github.com/tofuengine/tofu&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While this release may not be as groundbreaking as some of the previous ones, it is still incredibly important as it signifies the beginning of a new era.&lt;/p&gt;

&lt;p&gt;There are two significant reasons for this.&lt;/p&gt;

&lt;p&gt;I hinted at the arrival of some major changes in a &lt;a href=&quot;/tofu-engine-10&quot;&gt;previous post&lt;/a&gt;, which you can find &lt;a href=&quot;/tofu-engine-10&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let’s delve into these changes a bit.&lt;/p&gt;

&lt;h2 id=&quot;the-rendering-system&quot;&gt;The Rendering System&lt;/h2&gt;

&lt;p&gt;As you may already know, Tofu Engine currently utilizes a custom software-rendering approach. I take great pride in this achievement as it allowed me to implement algorithms I extensively worked on during the ’90s. Unfortunately, some of this knowledge has become lost over the past two decades. Back in the day, we were all busy crafting mind-bending roto-zoomers, but nowadays, only a select few know what they are and how to implement them. Additionally, this approach enabled me to incorporate unique and specific effects like Mode-7 transformations and Copper-lists.&lt;/p&gt;

&lt;p&gt;However, running a software renderer on modern hardware… well, let’s just say it can be far from optimal.&lt;/p&gt;

&lt;p&gt;It’s a legitimate choice if one aims to create a virtual retro-machine like &lt;a href=&quot;https://www.lexaloffle.com/pico-8.php&quot;&gt;pico-8&lt;/a&gt;, where the FPS and overall performance are intentionally limited. However, for a general-purpose game engine designed to run on modern hardware and support complex games, it’s not the most sensible choice.&lt;/p&gt;

&lt;p&gt;Therefore, over the past year, I’ve been experimenting with reimplementing most of the features in Tofu Engine, leveraging the power of the GPU as much as possible. This involves transitioning back to full &lt;a href=&quot;https://www.opengl.org/&quot;&gt;OpenGL&lt;/a&gt; (or &lt;a href=&quot;https://www.vulkan.org/&quot;&gt;Vulkan&lt;/a&gt;) usage, which, at the moment, is only utilized as a cross-platform way to present the framebuffer.&lt;/p&gt;

&lt;p&gt;Fortunately, many of the engine’s current features can be reimplemented with minimal changes. Some may require some redesigning (leveraging fragment shaders, if needed), such as the stencil/alpha/tiled blitting and Copper-lists. Others may be permanently removed, like the Mode-7 inspired transformations.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I need to carefully weigh their importance and eliminate what isn’t truly necessary. For instance, the aforementioned Mode-7 transformations may be cool and unique, but it serves little purpose in a real-world scenario and can likely be discarded. On the other hand, certain Copper-list features have practical applications and can be maintained with some minor simplification.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If all goes well, this will results in a much more efficient game-engine, in its utilization of hardware resources. It will also reduce overall power consumption, as running an uncapped software renderer for FPS heavily drains the machine’s power. You notice this when the fans start making some noise!&lt;/p&gt;

&lt;p&gt;Let’s hope that all the effort put into this endeavour will prove worthwhile! :)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;( and let’s also hope to fix that diamond-rule issue that inspired me to implement a software renderer back in 2019, as I was facing challenges in ensuring pixel-perfect blitting )&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;abstraction&quot;&gt;Abstraction&lt;/h2&gt;

&lt;p&gt;When I initially began working on &lt;strong&gt;Tofu Engine&lt;/strong&gt;, my goal was to create a straightforward environment. An easily accessible sandbox with all the essential components ready to be combined.&lt;/p&gt;

&lt;p&gt;However, as development progressed, I found it increasingly challenging to restrain myself. I ended up making the engine more and more &lt;em&gt;low-level&lt;/em&gt; and generic, which is a tendency of mine, as I prefer creating solutions that are applicable to a wide range of situations rather than specific ones.&lt;/p&gt;

&lt;p&gt;This led to something that, to some extent, resembled other game engines (e.g. &lt;a href=&quot;https://love2d.org/&quot;&gt;Löve&lt;/a&gt;, which I always cited as an influence), offering a scriptable framework that provides everything one would need to create almost any type of game but without specific assistance for game development.&lt;/p&gt;

&lt;p&gt;This is particularly evident in the way the game loop interacts with the game “instance” (let’s refer to its class/object as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main&lt;/code&gt;), which involves calling the following methods:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main.process()&lt;/code&gt;: called on each iteration after updating the input state,&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main.update()&lt;/code&gt;: called at regular intervals to update the game state, and&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main.render()&lt;/code&gt;: called on every iteration to present the graphics to the user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While this approach is undoubtedly correct, it lacks abstraction of the engine’s internal workings. The scripted code matches almost one-to-one the engine’s one. Where’s the benefit of the abstraction that an engine should grant? It seems like we are coding for a virtual console for which Lua is the native language… :&amp;gt;&lt;/p&gt;

&lt;p&gt;Furthermore, there are suboptimal design choices in this approach. For example, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Main.render()&lt;/code&gt; method is called on every frame, meaning we frequently cross the C-to-Lua boundary only to subsequently cross back from Lua to C for each drawing operation. It works, but it’s far from efficient.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;( well, it does work, nonetheless :D )&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Is this really what I envision for my game engine? I must admit that it deviates significantly from my initial idea, and I fear that, in the long run, developers would end up writing excessive boilerplate code even for the simplest tasks.&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;

&lt;p&gt;As I grapple with this realization, it has become evident that a paradigm shift is necessary at this point. I need to go back to square one and completely rethink this aspect.&lt;/p&gt;

&lt;p&gt;I’m currently taking notes and starting the ground-up redesign of these two crucial parts of the engine.&lt;/p&gt;

&lt;p&gt;I anticipate that implementation will commence soon.&lt;/p&gt;

&lt;p&gt;Probably. :)&lt;/p&gt;
</description>
        <pubDate>Mon, 29 May 2023 00:00:00 +0000</pubDate>
        <link>https://mode13h.dev/tofu-engine-v0_13_0/</link>
        <guid isPermaLink="true">https://mode13h.dev/tofu-engine-v0_13_0/</guid>
        
        <category>release</category>
        
        <category>redesign</category>
        
        
        <category>tofu-engine</category>
        
        <category>devlog</category>
        
      </item>
    
  </channel>
</rss>
