<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Angelo Theodorou</title>
    <description>The latest articles on DEV Community by Angelo Theodorou (@encelo).</description>
    <link>https://dev.to/encelo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3450913%2F8e93bef9-5833-466c-a639-b9f5fbcffa71.jpg</url>
      <title>DEV Community: Angelo Theodorou</title>
      <link>https://dev.to/encelo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/encelo"/>
    <language>en</language>
    <item>
      <title>nCine Dev Update #22</title>
      <dc:creator>Angelo Theodorou</dc:creator>
      <pubDate>Sun, 21 Sep 2025 19:31:23 +0000</pubDate>
      <link>https://dev.to/encelo/ncine-dev-update-22-3pip</link>
      <guid>https://dev.to/encelo/ncine-dev-update-22-3pip</guid>
      <description>&lt;p&gt;Welcome back to another development update for the nCine, covering what has been accomplished from January 2025 to August 2025.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introspective Sort
&lt;/h2&gt;

&lt;p&gt;Back in December 2023, the author of Jazz² Resurrection reported a crash when sorting a render queue with more than 3000 commands. The sequence was unbalanced and quicksort recursion went too deep, overflowing the stack.&lt;/p&gt;

&lt;p&gt;He suggested switching to introspective sort (a hybrid of quicksort, heapsort, and insertion sort) which is exactly what I ended up implementing, using the same thresholds as many standard implementations.&lt;/p&gt;

&lt;p&gt;The algorithm sets a maximum quicksort depth at twice the base-2 logarithm of the number of elements. Up to that depth, recursive quicksort partitioning is used, which is safe for slightly unbalanced trees. If the depth is exceeded, the algorithm falls back to an iterative heapsort, avoiding stack growth. Finally, for partitions smaller than 16 elements, insertion sort takes over, as it's faster on small ranges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global Game Jam 2025
&lt;/h2&gt;

&lt;p&gt;I took part in the Global Game Jam 2025 in my city, where we built a game using nCine. After the jam I polished it and released it on GitHub as &lt;a href="https://github.com/encelo/WetPaper" rel="noopener noreferrer"&gt;Wet Paper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Compared to the jam version, I added several features: a complete menu system, player statistics, TOML-based configuration, custom blur and refraction shaders, crossfading for music, a low-pass filter when pausing, and joystick vibration.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/jvhKzdlgR4Q"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The jam also gave me a chance to improve nCine itself with new features and quality-of-life tweaks. For example, the engine now keeps track of the previous frame state for keyboard and joystick input, making it trivial to check exactly when a button was pressed or released.&lt;/p&gt;

&lt;p&gt;I also made the vector classes return a zero vector when the length is too short (like many other engines), renamed &lt;code&gt;interval()&lt;/code&gt; to &lt;code&gt;frameTime()&lt;/code&gt; and &lt;code&gt;apptest_scene&lt;/code&gt; to &lt;code&gt;apptest_gui&lt;/code&gt; for clarity, and fixed broken alpha getters in the &lt;code&gt;SceneNode&lt;/code&gt; class. A color setter override that accepted a float parameter has been renamed, and a method was added to set a &lt;code&gt;TimeStamp&lt;/code&gt; to the current time without allocating a new object.&lt;/p&gt;

&lt;p&gt;Working on custom shaders for Wet Paper also led me to fix viewport clearing logic and repair OpenGL debug groups, which hadn't been working properly for viewports.&lt;/p&gt;

&lt;p&gt;One of the last additions was joystick vibration. SDL2's rumble API (&lt;a href="https://wiki.libsdl.org/SDL2/SDL_JoystickRumble" rel="noopener noreferrer"&gt;&lt;code&gt;SDL_JoystickRumble()&lt;/code&gt;&lt;/a&gt;) is quite barebones: you set the intensity for the two motors and a duration in milliseconds, but each call cancels the previous effect. That's why I started working on a &lt;code&gt;JoyVibrator&lt;/code&gt; class to interpolate motor intensities independently. The work isn't finished yet and lives in a local &lt;code&gt;joy_vibrator&lt;/code&gt; branch. 😅&lt;/p&gt;

&lt;h2&gt;
  
  
  Presentation at /dev/games
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fncine.github.io%2Fimg%2Fposts%2FDevGames2025.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fncine.github.io%2Fimg%2Fposts%2FDevGames2025.jpg" title="Presenting at /dev/games 2025" alt="Presenting at /dev/games 2025"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On June 5th I was invited to Rome to present my 14-year journey with nCine at the &lt;a href="https://devgames.org/" rel="noopener noreferrer"&gt;/dev/games&lt;/a&gt; conference.&lt;/p&gt;

&lt;p&gt;It was both a chance to catch up with friends and an opportunity to show developers and students the craft, the struggles, and the technical insights involved in sustaining a long-term project like this.&lt;/p&gt;

&lt;p&gt;You can browse the &lt;a href="https://encelo.github.io/nCine_14Years_Presentation/" rel="noopener noreferrer"&gt;presentation&lt;/a&gt; online. I made it with Slidev and published the Markdown source on GitHub. The talk was recorded and should appear on the official YouTube channel later this year.&lt;/p&gt;

&lt;h3&gt;
  
  
  RenderDoc integration update
&lt;/h3&gt;

&lt;p&gt;While preparing fresh screenshots for the talk, I revisited the RenderDoc integration and updated it to the latest 1.6.0 API. This allowed me to add features such as capture titles, automatically opening the RenderDoc UI after a capture, and enabling API validation and callstack capturing by default when using an OpenGL debug context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run-time Environment Variables
&lt;/h2&gt;

&lt;p&gt;Here's a small but useful quality-of-life change. You can now override &lt;code&gt;AppConfiguration&lt;/code&gt; values at runtime through environment variables instead of recompiling your application.&lt;/p&gt;

&lt;p&gt;This makes it easy to test your game under varying conditions: from sound frequencies and shader cache usage to window resolutions, render command pool size, or log levels.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NCINE_APPCFG_CONSOLE_LOG_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0 &lt;span class="nv"&gt;NCINE_APPCFG_FILE_LOG_LEVEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3 &lt;span class="nv"&gt;NCINE_APPCFG_LOG_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"game.txt ./my-ncine-game
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command disables console logging while redirecting it to a file of your choice. Combine this with scripts and you can quickly test multiple configurations. More details are available in the wiki &lt;a href="https://github.com/nCine/nCine/wiki/AppCfg-EnvVars" rel="noopener noreferrer"&gt;article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crashpad integration
&lt;/h2&gt;

&lt;p&gt;More than three years ago I began integrating Google Crashpad, a modern replacement for the now unsupported CrashRpt that I had used in &lt;code&gt;ncParticleEditor&lt;/code&gt;. Crashpad is cross-platform, actively maintained by Google (they use it in Chrome), and runs as an out-of-process component, a perfect fit for my requirements.&lt;/p&gt;

&lt;p&gt;The tricky part was Android, where distributing the &lt;code&gt;crashpad_handler&lt;/code&gt; executable can trigger security restrictions depending on OS version. The solution was to ship it disguised as a JNI library and use &lt;code&gt;nativeLibraryDir()&lt;/code&gt; to retrieve its location.&lt;/p&gt;

&lt;p&gt;Another addition is the ability to extract debug info files to a user-specified directory without enabling Crashpad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cmake &lt;span class="nt"&gt;-S&lt;/span&gt; nCine &lt;span class="nt"&gt;-B&lt;/span&gt; nCine-build &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;NCINE_DEBUGINFO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;EXTRACT &lt;span class="nt"&gt;-D&lt;/span&gt; &lt;span class="nv"&gt;DEBUGINFO_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CMAKE_BINARY_DIR&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/symbols
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way you can upload debug symbols to platforms like Sentry, which itself uses Crashpad internally.&lt;/p&gt;

&lt;h2&gt;
  
  
  Array improvements
&lt;/h2&gt;

&lt;p&gt;Even the well-proven &lt;code&gt;Array&lt;/code&gt; class had room for improvement.&lt;/p&gt;

&lt;p&gt;First, I fixed a subtle bug with insertions and removals in the middle: the old implementation overwrote elements without destroying them first. Thanks to &lt;a href="https://github.com/W4RH4WK" rel="noopener noreferrer"&gt;W4RH4WK&lt;/a&gt; on Discord for reporting it! There's now a unit test checking construction, destruction, and assignment counts for these operations.&lt;/p&gt;

&lt;p&gt;Second, I reworked the type-trait helpers in &lt;code&gt;utility.h&lt;/code&gt;. They now distinguish between trivially copyable, movable and copyable, movable-only, copyable-only, and fully non-movable/non-copyable objects.&lt;br&gt;
Two new &lt;code&gt;setCapacity()&lt;/code&gt; implementations now use tag dispatching to select the right behavior based on the Array class's template type. Thanks to this, you can create Array instances containing non-copyable and non-movable objects, with the restriction that arrays must be empty to resize and new elements can only be added at the back via &lt;code&gt;emplaceBack()&lt;/code&gt;.&lt;br&gt;
This wasn't even compiling before. 😮&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-threaded Job System
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fencelo.github.io%2Fimages%2FTracy_apptest_jobsystem.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fencelo.github.io%2Fimages%2FTracy_apptest_jobsystem.png" title="Tracy capture of apptest_jobsystem" alt="Tracy capture of apptest_jobsystem"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The star of this update is the new job system. After months of iteration, it has finally stabilized in structure and API.&lt;/p&gt;

&lt;p&gt;Jobs now use opaque &lt;code&gt;JobId&lt;/code&gt; handles that encode both a pool index and a generation number, which makes detecting stale IDs easy. I spent a long time experimenting with a fully lock-free job pool but couldn't get correct behavior. The final design uses per-thread job caches and a global pool protected by a mutex.&lt;/p&gt;

&lt;p&gt;Worker synchronization now uses semaphores instead of a mutex + condition variable pair to wake threads when new jobs are available. This avoids the extra lock/unlock overhead and makes the wakeup path more direct. On each platform the fastest available primitive is used: on Linux a futex-based userspace semaphore, on Windows &lt;a href="https://learn.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitonaddress" rel="noopener noreferrer"&gt;&lt;code&gt;WaitOnAddress()&lt;/code&gt;&lt;/a&gt; with atomics instead of a kernel semaphore object, and on macOS a Grand Central Dispatch semaphore instead of a pthreads implementation.&lt;/p&gt;

&lt;p&gt;To tame the many threading issues during development, I added &lt;code&gt;jobsystem_debug.h&lt;/code&gt;, which lets you enable Tracy zones and plots, statistical counters, additional logs, and job state tracking via compile-time flags. These debug tools have been lifesavers.&lt;/p&gt;

&lt;p&gt;There's also a serial job system: if you set a single-thread mode in &lt;code&gt;AppConfiguration&lt;/code&gt; you'll get the same API without synchronization, perfect for debugging or measuring scalability.&lt;/p&gt;

&lt;p&gt;A recent commit also added a handle class with an object-oriented API over job IDs, new job state flags to prevent double submissions and support cancellation, and a new submit call to allow for multiple jobs to be submitted at once.&lt;/p&gt;

&lt;h3&gt;
  
  
  CPU Topology
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fencelo.github.io%2Fimages%2FCPU_Topologies.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fencelo.github.io%2Fimages%2FCPU_Topologies.png" title="CPU Topologies Diagram" alt="CPU Topologies Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I completely reworked how the thread pool is created and how affinity is set, making the system topology-aware.&lt;/p&gt;

&lt;p&gt;The idea is to sort cores by speed, to leave the main thread unpinned, and to start pinning worker threads from the second fastest physical core.&lt;/p&gt;

&lt;p&gt;I have tested it on some of my devices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;On a Ryzen 9 6900HS (8C/16T), it creates 7 workers pinned to physical cores, leaving the main thread free.&lt;/li&gt;
&lt;li&gt;On an Intel i5-1235U (2P + 8E, 10C/12T), it creates 9 workers: one on the second performance core and eight on the efficiency cores, with the main thread unpinned.&lt;/li&gt;
&lt;li&gt;On a Mac Mini M1 (4P + 4E), it pins 7 workers, leaving the main thread unpinned and the first performance core free.&lt;/li&gt;
&lt;li&gt;On a Snapdragon 8 Gen 3 (1Pr + 3P + 2P + 2E), it uses sysfs &lt;code&gt;cpu_capacity&lt;/code&gt; values to pin 7 workers across the three weaker clusters, leaving the main thread unpinned and the Prime core free.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This could eventually allow more advanced scheduling in the future, with certain job tags mapped to faster or slower cores depending on priority.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusions
&lt;/h3&gt;

&lt;p&gt;The best part: the job system is fully exposed to applications. You can try it right now in the new &lt;code&gt;apptest_jobsystem&lt;/code&gt; test. 🙌&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;job_system&lt;/code&gt; branch is already live and up to date, though it needs more testing before merging. Meanwhile, I've begun work on a data-oriented ECS, an ideal testing ground for the job system. More on that in the next update.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minor Changes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Added conversion functions between &lt;code&gt;Vector*i&lt;/code&gt; and &lt;code&gt;Vector*f&lt;/code&gt;, and between &lt;code&gt;Recti&lt;/code&gt; and &lt;code&gt;Rectf&lt;/code&gt; classes&lt;/li&gt;
&lt;li&gt;Updated &lt;code&gt;README&lt;/code&gt; with documentation links and screenshots 📷&lt;/li&gt;
&lt;li&gt;Added new dirty bits to nodes (thanks to &lt;a href="https://github.com/jugilus" rel="noopener noreferrer"&gt;Jugilus&lt;/a&gt;) to avoid redundant transformations of culled nodes&lt;/li&gt;
&lt;li&gt;Fixed a long-standing bug with string capacity changes when using custom allocators&lt;/li&gt;
&lt;li&gt;Updated GitHub Actions runners: added macOS 15 and Ubuntu 24.04, retired VS2019&lt;/li&gt;
&lt;li&gt;Vector, matrix, and quaternion classes now have inequality operators 😄&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>14 Years Building My Own Game Engine</title>
      <dc:creator>Angelo Theodorou</dc:creator>
      <pubDate>Fri, 22 Aug 2025 10:28:15 +0000</pubDate>
      <link>https://dev.to/encelo/14-years-building-my-own-game-engine-4hom</link>
      <guid>https://dev.to/encelo/14-years-building-my-own-game-engine-4hom</guid>
      <description>&lt;p&gt;For the past 14 years I've been building and maintaining my own 2D game engine, &lt;a href="https://github.com/nCine/nCine" rel="noopener noreferrer"&gt;nCine&lt;/a&gt;. In June I gave a talk at &lt;a href="https://devgames.org" rel="noopener noreferrer"&gt;/dev/games&lt;/a&gt;, a two-day game development conference in Rome, about my journey developing it.&lt;br&gt;
What started as a side project slowly grew into a long-term companion through different stages of my career in the games industry.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the nCine? ⚙️
&lt;/h2&gt;

&lt;p&gt;nCine is a cross-platform 2D framework for games, tools, and prototypes. It runs on Windows, Linux, macOS, Android, Raspberry Pi, and even the web through Emscripten. It's written in C++11 with Lua bindings, emphasizes performance and optimization, and is available under the MIT license on GitHub.&lt;/p&gt;

&lt;p&gt;Above all, nCine has always been a learning opportunity, both for me and (hopefully) for its users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Build Another Engine? 🤔
&lt;/h2&gt;

&lt;p&gt;The first commit came from a mix of frustration and curiosity. At the time, I was working on GUI code for games and daydreaming about graphics programming. Writing my own engine was both an escape and an education.&lt;/p&gt;

&lt;p&gt;The project gave me a chance to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dive deep into C++ templates, generic programming, custom allocators, and multithreading.&lt;/li&gt;
&lt;li&gt;Explore rendering techniques and cross-platform development.&lt;/li&gt;
&lt;li&gt;Build a codebase I could use for demos and experiments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over time, the motivation changed. These days, the excitement comes from seeing others pick it up, push its limits, and create with it. If someone builds something beautiful with nCine, that would mean more than any benchmark.&lt;/p&gt;

&lt;p&gt;And yes, I also believe the world benefits from more custom engines. Too much consolidation risks stagnation. The history of game dev is no stranger to bespoke engines that did things no off-the-shelf solution would have achieved.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Hobby to Career Companion
&lt;/h2&gt;

&lt;p&gt;The first commit was in June 2011. At the time, I was in Italy, working at a small indie company. I started developing on Arch Linux, using CMake, GCC, and Qt Creator. Within a couple months, I had something running on Android too.&lt;/p&gt;

&lt;p&gt;The engine followed me everywhere, from Italy to the UK, from the UK to Sweden, and finally to Spain.&lt;/p&gt;

&lt;p&gt;At each stage, I rewrote or refactored parts of the code as my knowledge grew. The nCine has almost become a mirror of my own professional journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Highlights 💡
&lt;/h2&gt;

&lt;p&gt;A few features I'm particularly proud of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Foundation: No use of STL, the nCine Template Library (nCTL) provides containers, iterators, algorithms, smart pointers. I also have my wrappers for threads, atomics, and filesystem.&lt;/li&gt;
&lt;li&gt;Rendering: OpenGL 3.3 backend, automatic batching, custom user shaders and viewports for post-processing.&lt;/li&gt;
&lt;li&gt;Audio: OpenAL-based sound system with WAV and Ogg streaming support, OpenAL EFX effects and filters.&lt;/li&gt;
&lt;li&gt;Input: Full gamepad support across platforms, including Android via JNI integration. Multiple backend support: GLFW, SDL2, Qt5.&lt;/li&gt;
&lt;li&gt;Performance: Custom allocators, SIMD experiments with SSE and NEON, multi-threaded job system.&lt;/li&gt;
&lt;li&gt;Tooling: Integration with Dear ImGui, the Tracy frame profiler, and RenderDoc.&lt;/li&gt;
&lt;li&gt;Ecosystem: From Pong clones to path tracers, from prototypes to artist tools, the engine became the base for a surprising range of side projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Lessons Learned 👨‍🏫
&lt;/h2&gt;

&lt;p&gt;Looking back over 14 years, a few patterns emerge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rewrite with purpose. Don't be afraid to throw away code, but only when you know why the new version will be better. For example, I started with an OpenGL 1 fixed-pipeline because I wanted the simplest rendering to focus on other things first, later I rewrote it a couple times to support newer technology.&lt;/li&gt;
&lt;li&gt;Side projects can outlast companies. nCine became a constant thread in my career, something I enjoyed no matter where I worked.&lt;/li&gt;
&lt;li&gt;Tests and docs are future-proofing. Over 25,000 of the 120,000 code lines in nCine are dedicated to unit tests. Documentation (Doxygen and LDoc) isn't just for others, it's for my future self.&lt;/li&gt;
&lt;li&gt;Community matters. Even a small user base can keep you motivated. Seeing others stress-test nCine pushed it further than I ever could alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next 🚀
&lt;/h2&gt;

&lt;p&gt;I'm finishing a multi-threaded job system and already exploring how to use it to speed things up. I will apply some data oriented design principles to rewrite core parts of the engine to be more cache-friendly, while probably also introduce some ECS foundations.&lt;br&gt;
After that who knows, maybe I will start working on the Vulkan backend I've been thinking about for years.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;If I were starting today, I might choose different tools or even a different language. But I'm glad I stuck with nCine. It taught me more than I ever expected, gave me interview material, personal satisfaction, and a community of curious developers.&lt;/p&gt;

&lt;p&gt;The slides from my /dev/games talk are online:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://encelo.github.io/nCine_14Years_Presentation/" rel="noopener noreferrer"&gt;Interactive slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://encelo.github.io/nCine_14Years_Presentation/nCine_14Years.pdf" rel="noopener noreferrer"&gt;PDF version&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the engine itself is open source here: &lt;a href="https://ncine.github.io" rel="noopener noreferrer"&gt;https://ncine.github.io&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>opensource</category>
      <category>gamedev</category>
      <category>cpp</category>
    </item>
  </channel>
</rss>
