From 3e0f620a933cf2a9325d051e87952edb1c3f9270 Mon Sep 17 00:00:00 2001 From: Akshay Date: Wed, 17 Mar 2021 17:59:43 +0530 Subject: new post: sdl2 devlog --- posts/SDL2_devlog.md | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 posts/SDL2_devlog.md (limited to 'posts') diff --git a/posts/SDL2_devlog.md b/posts/SDL2_devlog.md new file mode 100644 index 0000000..0b05c90 --- /dev/null +++ b/posts/SDL2_devlog.md @@ -0,0 +1,139 @@ +I have been working on an editor for the [One Bit +Image](https://git.peppe.rs/graphics/obi/about) file format in +Rust and SDL2. This entry in my blog follows my progress on +the editor. The days are listed in reverse chronological +order, begin from the bottom this is your first time on this +page. + +### Day 10 + +I started reading up on dithering methods and half-toning, I +wanted to create a dithering brush that would automatically +produce popular dithering patterns. The method that caught +my eye (and also the one used most often in pixel art), was +Bayer's ordered dithering. When applied to a black and white +image, each pixel, based on its intensity, is mapped to a +4x4 grid of pixels. A completely empty (completely black) +4x4 grid represents zero intensity, and a filled 4x4 grid +represents full intensity. Bayer's ordered dithering can +produce 15 steps of intensity between zero and full (by +switching on exactly 1 pixel more at each level), thus, +being able to draw 17 "shades" from white to black. Creating +a dithering brush from here was fairly trivial. Our pixmap +is supposed to represent the final dithered image, it must +be divided into 4x4 grids. Each grid is colored based on the +intensity of the brush passing over it: + +![Day 10](https://u.peppe.rs/Mn.png) + + +### Day 9 + +I started working towards an interface. I like the idea of a +largely read-only HUD, i. e., an interface that simply +describes the state of the application. Changes to this +state are initiated via keybinds or text commands. I am +proud of the symmetry indicator; `-` for horizontal +symmetry, `|` for vertical symmetry, `+` for radial +symmetry. + +![Day 9](https://u.peppe.rs/hx.png) + +### Day 8 + +One of my favourite features of GIMP was symmetric editing. +I added some coordinate geometry primitives to my pixmap +abstraction, allowing for mirroring and reflecting figures +about lines or points. The result was an ergonomic function +that applies symmetry to any painting operation, (undo/redo +works as expected): + +```rust +let line = self.pixmap.get_line(start, end); +let sym_line = self.symmetry.apply(&line); +for point on line.extend(sym_line) { + // draw to window +} +``` + +![Day 8](https://u.peppe.rs/B1.mp4) + +### Day 7 + +Bresenham saves the day again! This time, I implemented his +line drawing algorithm, to, well, draw lines. Each point on +the line is then "buffed" based on the active brush size. +Today's changes fit in very well with the undo system and +the brush size feature. Creating the right abstractions, one +at a time :) + +![Day 7](https://u.peppe.rs/xt.mp4) + + +### Day 6 + +I extended Bresenham's algorithm to draw not just circle +outlines, but also generate their fills. Unlike Bresenham's +algorithm, this variant generates points for two quadrants +at once, these points are mirrored over the dividing axis to +generate the other two quadrants. + +![Day 6](https://u.peppe.rs/f3.png) + +### Day 5 + +I discovered and implemented Bresenham's algorithm for +efficient circle drawing. The algorithm allowed for sized +circular brushes, something I really liked from GIMP. Very +convenient that the Wikipedia page for Bresenham's algorithm +also includes a section about optimizing for integer based +arithmetic. I managed to abstract out another giant +component of the application, the pixmap. Any image is just +a grid of pixels (a pixmap), where the pixel's value is +decided by the application (1-bit in my case). I could +potentially extend the application to a 24-bit image editor! + +![Day 5](https://u.peppe.rs/Kh.mp4) + + +### Day 4 + +I created a generic "undo stack" data structure that allows +for infinite "undos" and "redos". Every modification +operation to the grid is persisted to the application state. +A couple of keybinds allow the user to revert and re-apply +these operations! I expect abstracting this component will +come in handy down the line. + +![Day 4](https://u.peppe.rs/w5.mp4) + + +### Day 3 + +I implemented the bare minimum required to call the program +and "editor". The application displays a grid, tracks mouse +events, paints white to the canvas on left click, and black +to the canvas on right click. I created a make-shift MVC +architecture à la Elm in Rust. + +![Day 3](https://u.peppe.rs/GF.mp4) + +### Day 2 + +I started figuring out event handling today. Implemented a +couple of keybinds to zoom in/out of the drawing area. +Conversions of SDL2 coordinates (measured in signed 32 bit +integers) to my internal "drawing area" coordinates +(measured in unsigned 32 bit integers) is very annoying. +Hopefully the unchecked conversions won't haunt me later. + +![Day 2](https://u.peppe.rs/L4.mp4) + +### Day 1 + +Getting started with Rust and SDL2 is very straightforward. +The `rust-sdl2` library contains some detailed examples that +allowed me to get all the way to drawing a grid from a +`Vec`: + +![Day 1](https://u.peppe.rs/Ma.png) -- cgit v1.2.3