⚡ Zig Guide LiveUnofficialbut fully verified
✓ Zig 0.18.0-dev.624+b7f2c6d8fWhat's newOn an older Zig?Blograylib-zig

Graphics

This section builds a renderer from an array of bytes, with no graphics library under it. Start with a framebuffer and save the framebuffer as a PNG. The next chapters draw lines and circles, rasterize triangles with barycentric coordinates, composite with alpha, and mix colours in linear light. Then supersampling makes jagged edges smooth. After that, the chapters process the buffer as an image. Brightness and contrast are lookup tables, and blur and Sobel edges are convolution kernels. Grayscale and sepia are colour matrices, auto-levels come from a histogram, and median filters remove noise. A chapter also shows the half-pixel bug that shifts a resized image. The last chapters put the buffer in a canvas to draw into part of it, map a texture across a triangle, and move a shape with an affine matrix. Everything before the last chapter runs in your browser.

Each program in this section is the smallest program that makes one idea visible. The programs fix their own buffer sizes. They do not have the error handling and the fast paths that a real renderer needs. They print ASCII so that you can check the result by eye. Where colour is important, the programs also paint the picture, and CI checks the pixels by their hash. Read the programs for the arithmetic and the reasons behind it, not as code to copy into a project.

  1. A framebuffer is an array of bytes. Every chapter here is arithmetic on that array, with no library under it.
  2. Rasterization decides which pixels a shape covers. Antialiasing decides how much of each pixel the shape covers, and that is why antialiasing costs more.
  3. Blur, sharpen and edge detection are one operation with different numbers in the kernel.
  4. Resampling shifts the image by half a pixel unless you sample pixel centres. The shift looks like a rounding bug, but it is not a rounding bug.

23 chapters.

  • A Framebuffer Is an ArrayRow-major layout, top-left origin, packed pixels, and a putPixel that clips.
  • Write an Image FilePPM, the image format that you can write without a library, and the one strict rule that is easy to break.
  • Write a PNGA signature, three chunks and a CRC on each chunk. The writer filters the pixels, then compresses them with the zlib in the standard library.
  • LinesBresenham's algorithm: one add and one compare per pixel, integers only.
  • CirclesCompare squared distances, loop over the bounding box, and let putPixel clip.
  • Alpha BlendingSource-over compositing in integers, the reason for the /255, and the reason that order is still important.
  • Linear LightA stored byte is not an amount of light. Decode, mix, encode, with both tables built by the compiler.
  • Rasterize TrianglesEdge functions tell inside from outside, and the same three numbers interpolate values across the face.
  • AntialiasingCoverage is alpha. Do the inside test sixteen times for each pixel, and the jagged edges disappear.
  • Per-Pixel TransformsBrightness, contrast, threshold and invert are all one table lookup, and brightness needs Zig's saturating add.
  • ConvolutionBlur, sharpen and Sobel are one loop with different numbers in it. The two bugs are always the border and the buffer.
  • Colour MatricesGrayscale, sepia and saturation are one 3x3 matrix. A chain of these matrices multiplies into one matrix before the program changes the image.
  • Histograms and LevelsCount what the image contains, and get the correction table from the counts. Auto-levels, equalization, and why to apply them to luma.
  • Median and Rank FiltersA convolution cannot ignore a value. Sort the neighbourhood, and one function is a denoiser, an eroder or a dilator. The index decides which.
  • Scale and ResampleNearest, bilinear and box filters, the half-pixel bug, and why a downscale without a filter makes fine detail into a solid bar.
  • Bitmap TextA glyph is a small rectangle of bits. To draw text, copy those bits.
  • Sprites and TransparencyA copy of a rectangle is easy. The important feature is the decision about which pixels not to copy.
  • A Scene GraphPosition each thing relative to its parent. When the parent moves, everything below the parent moves with it.
  • A Bar ChartOne division changes numbers into pixels. If the division is wrong, the chart misleads the reader.
  • A Canvas Is a ViewFour fields, not a slice. Each routine draws inside a region, and the routine does not know that the canvas is a region.
  • Texture MappingThe triangle already interpolates. Point the triangle at a second image, and it interpolates coordinates into that image, not colours.
  • TransformsTo move, turn and resize a shape is one operation. To combine them is a multiply, and you cannot select its order freely.
  • Onto the ScreenThe same buffer, given to X11 through translate-c, and what changes on Wayland.