↓ Skip to main content
  1. Gremlin Engine/

Gremlin Dev Log: April 2026 - Sawdust in the Shaders

VeraShackle
Author
VeraShackle
Tales of computers, gadgets & gizmos.
Gremlin Dev Log - This article is part of a series.
Part 4: This Article

Not a game in sight…
#

OK, confession time. April was the busiest month of the year so far for Gremlin, and almost none of it was about games. My CNC router project, CNCWorkbench, wanted to load designs, trace bitmaps, generate toolpaths and simulate the cut - and Gremlin had to grow a lot of new muscle to keep up. This is an App that I want to use with a desktop CNC in a very interactive way.

This is the ‘solve the problem in front of me and let the structure emerge’ idea in action. I didn’t plan to write a geometry library. One turned up because a project needed it.

This is also a bit of an overlap with my work life - but I have two specific requirements for this personal CADCAM project; I want a simple inconsequential coding space to work through crazier ideas that only may end up being usable at work, but I also have a sad, barely-used, Prusa printer by my desk. I would really like to generate something printable from first principles. Oh, and I have a vague electronics project in the back of my mind that may need circuit boards and enclosures. Obviously the solution is to build your own CADCAM library, right?

Geometry grows up
#

Following the end-of-March split, Gremlin::Geometry became a proper home for:

  • cylinder and capsule volumes, and line segments,
  • path simplification algorithms, moved over from CNCWorkbench’s toolpath code,
  • translating spans and contours,
  • subtracting multiple intervals in one pass, to cut down on allocations and comparisons.

The CAD document also gained a CadBitmap with boundary tracing, plus a small set of image-processing filters. So now a scanned or drawn image can be turned into contours to cut. CNCWorkbench was loading and tracing bitmaps the same day. This is really the first step on the way to a circuit trace engraving solution.

Simulating sawdust
#

This was the deep end. To show what a cut will look like, you need a model of the material that the tools can remove from. Gremlin now has a tri-dexel stock model: three grids of rays through the block, one along each axis, where every ray stores a sorted list of solid intervals. Cutting is interval subtraction; adding material is interval union. Simple, right?

Well, the maths is simple. The model renders by ray-marching in a shader, and most of the month went into getting the surface to look right. The key insight - written up in docs/DexelModel in the Gremlin repo - is that the interval boundaries are the surface. There’s nothing to search for. The hard part is deciding which of the three axes to believe at any given point, and getting a decent normal out of it:

  • One boundary in a cell? Use that axis’s height-field gradient. Easy.
  • Two or three? Blend their normals, weighted by distance.
    • The three-boundary case needs 12 texture reads, so it isn’t cheap. But it looks so much better that I decided it was worth it.

And of course there were the usual GPU adventures: a rounding error that only showed up on one particular GPU (fixed by flooring byte decodes), moiré patterns, seam noise, and surfaces being clipped too early by a fixed step count (now a theoretical maximum passed in as a uniform). A long-overdue camera frustum arrived to help keep performance sensible, and the CPU-side surface queries even got unit tests. Who am I?

Cutter shapes (V-bits and friends) can now subtract themselves from the stock, and within a week CNCWorkbench was animating a V-bit carving its way through a sine-wave surface. By the 12th the old flat material quad was gone and the real stock model was simulating the current toolpath.

CSG, OBJ & STL
#

Late in the month came an initial CSG implementation with creation and manipulation tools, mesh clean-up, serialisation and STL export. There’s basic OBJ saving now too (alongside the loading), and a native file-save dialog backed by tiny file dialogs.

Shaders that wire themselves up
#

A quieter change, but a really practical one. TriangleBatch and the GeometryRenderer now bind ‘standard’ uniforms automatically, working out what each one is for from its name (see Shader::InitUniformMap()). You fill in a FrameUniforms struct - projection, view, camera and lights - once per pass, and an ObjectUniforms struct per object or batch. Anything left null just gets skipped.

Far less boilerplate per shader, and a new shader ‘just works’ if it follows the naming convention. While I was in there I also fixed the newer shaders to use Gremlin’s precision macros properly - I’d quietly broken ES 2.0 support, which is rather the whole point of having an ES 2.0 baseline. Oops.

Goodbye, imgui
#

CNCWorkbench needed property panels, so Gremlin’s own UI grew an edit box, a translated TextInputEvent, and NumberEdit/TextEdit elements. Pocket toolpath settings were being edited through them within a couple of days.

And that was the last thing I needed imgui for. So, on 27 April, imgui went. The commit is 9 lines added and 70,937 lines deleted.

I like imgui a lot, honestly. But it was a big dependency doing a job my own UI can now do, and it meant a second UI paradigm living inside every app. Every dependency has to earn its keep, and this one had stopped earning.

Bits & bobs
#

  • Anti-aliased 3D line drawing, now used for all the line drawing in CNCWorkbench.
  • A reusable ModalState with different styles, which hands back the user’s response.
  • The perspective and orthographic cameras now behave consistently - similar view extents, panning and interaction.
  • No more 16-bit index limit for OBJ files, now that CPUIndexArray exists.
  • Float support in PropertyStore.
  • Joystick enumeration fixes, and a simple button mapping for my arcade USB joystick interface - which meant VictorVector’s own joystick-inversion fix was now correcting a bug that no longer existed. Out it came. VictorVector got a particle effect while I was at it.
  • Meanwhile Skirmish quietly started taking shape too, with its round and phase structure.

What’s next?
#

The CNC side is now a pile of capable parts - stock, CAD, CSG, toolpaths - that don’t really live together yet. Pulling them into something coherent is the obvious next job.

Gremlin Dev Log - This article is part of a series.
Part 4: This Article