Rendering Jigsaw Pieces on the Canvas vs. SDL

I've reached a bit of a milestone when it comes to rendering the puzzle pieces for my upcoming Peg City Parks Jigsaw game. I've been prototyping the game in JavaScript first, using the Canvas API. Once I feel I've reached a milestone, I'll go through a refactoring pass to clean up the code a bit, then port it over to C++ and SDL.

Latest Milestone - Rendering Group Shadows

My latest milestone allows me to group pieces together, draw a subtle inner bevel to make the pieces look like they're on cardboard, and provide a subtle shadow effect. I draw all of this using a CSS-style z-ordering, where each group of pieces has its own z-order. I loop through all of the groups, starting with the lowest z-order and finishing with the highest. Within each group:

  • Draw the group shadow first.
  • Draw each of the pieces on top of it.
  • In the future, I'll draw edge highlighting on top of that.

When the player attaches pieces, I use a smart insertion sort to keep the z-ordering of groups such that larger groups of pieces are kept further to the back.

Rendering on the Canvas

Shadow Effects on the Canvas

What you're seeing above is how things look with the group shadows, using the Canvas API in the JavaScript prototype. It's very subtle, but if you look closely at the edges of the pieces, there's a slight light-brown alpha feathering that hopefully makes it look like each piece is on cardboard.

On the Canvas, everything is drawn with paths, so it's effectively a vector-based system. The Canvas has properties that let you define the color, pattern, and width of lines; as well as the color, blur factor, and offset of shadows. It also lets you set up clipping regions along the paths, and gracefully handles multi-polygon paths. This is how the shadow of the group of pieces in the middle of the above screenshot is able to be cast with the hole in the pieces.

My overall rendering algorithm in JavaScript is based on path-related draw commands. It all gets routed through a single renderPath function that accepts a multi-polygon, a camera transform, and a bundle of line and fill properties.

The Canvas API is quite powerful in this regard, and it's very different than how the SDL port is going to operate.

Rendering with SDL

SDL does provide some basic vector primitives, such as lines, rectangles, and polygons. But it doesn't let you control line widths or patterns. SDL is much better at image processing, so I'll be using more of a raster-based approach with image masks.

I'm just about to start porting the rendering of puzzle pieces, so my vision of how it's going to work out could change as I go. But my plan is to use a technique called pixel erosion and dilation. Every puzzle piece will be stored as its own texture:

  • Draw the piece once using a cardboard texture.
  • Erode a few pixels worth away from the image mask.
  • Draw the piece again using the photo.

I also plan to create separate image masks for the edges of the pieces, so that I can apply things like highlighting effects. When the player is dragging a group of pieces, I want the option of showing them that it will successfully attach to other pieces. And it would be neat to be able to do brief animation effects when the player does attach pieces together, highlighting the edges that just finished connecting.

I'm hoping the SDL port can also mimic the way Canvas shadows look for groups of pieces. I quite like the look, and it's one area where the Canvas API is undeniably a better fit for this type of application...

If anybody is out there actually reading this, wish me luck porting this to SDL. I might need it! 😄