Implementation notes Rasterizing flowers. ---------------------------------------------------------------------- 0. Concept "Toaru Kagaku no Railgun" was one level above all other series that were broadcasting at the same time, and better than its predecessor "Toaru Majutsu no Index" in almost every regard. I was so inspired that I had to write this program. In particular, besides the trigger happy electromaster, the hardcore yuri teleporter, and the level 0 person whose figure is obviously too good for her age, there is Uiharu Kazari the hacker. The hacker bit left the greatest impression on me, for other people it's probably the flowers on her head. This program is about those flowers ^_^; ---------------------------------------------------------------------- 1. Flower shape The flowers appears to be quite colorful in the novel and manga versions. In the anime version, they are scaled down slightly to about four layers: - Small white flowers. - Larger orange flowers. - Some yellow stuff behind those. - Green leaves in the background. For this program, they are simplified even further to reduce code size: - No yellow stuff. - Solid green background. With some symmetry, it was possible to draw the outlined large and small flowers, using basically 4 bezier curves (16 control points total). The curves are then converted to list of line segments using De Casteljau's algorithm, which makes up the polygons used for rasterization in the next step. This step was also where I decided that Kazari would be implemented in OCaml, because all these path transformations could be done more cleanly in a functional language. ---------------------------------------------------------------------- 2. Rasterization After figuring out how flowers would be represented as polygons, I need some method to rasterize them into bitmaps. This part took a bit more thinking, but in the end I took a more simplistic approach and didn't implement some of the more complicated tricks. The simplistic approach works like this: - Find bounding box. - Rasterize each scanline of the boundingbox: + Find a point that is inside the polygon and on the scanline. + Binary search to find the two ends of the scanline. + Fill in all pixels between endpoints. - Anti-alias all polygons with supersampling. The scanlines were rendered such that they wraparound the edges of the bitmap, so the output is guaranteed to tile. The more complicated things I had planned was to render each polygon by tracing all the edges, drawing each edge with anti-aliasing. This approach could conceivably produce better quality images and run faster, but it takes a bit more code to do. I also thought about doing gamma correction, on both the edge tracing and the supersampling methods, but didn't spend more time on it because the current implementation is good enough. ---------------------------------------------------------------------- 3. Placement All other parts of Kazari were deterministic, but the placement and rotation of the flowers were deliberately random for variety. I tried to emulate how the flowers are placed in the anime version as follows: - Generate grid-like placement for the large orange flowers. - Place the small white flowers between the large ones. - Set the spacing and random jitter such that there would be some overlap between flowers. This placement scheme is also relatively simplistic, there is a bit of a tiling effect if the output is repeated enough times. I think it might look a bit nicer if the grid was hexagonal instead of rectangular, but like all other parts, this implementation was selected since the code is small, and the result looks decent enough. ---------------------------------------------------------------------- 4. Miscellaneous Regarding some extra files packaged in the archive: kazari_hq.ml - readers are encouraged to tweak kazari.ml to output different things, this file shows one possible modification: increased output size from 300 pixels to 600 pixels, and increased supersampling level from 4^2 subpixels per output pixel to 6^2. Other things that can be tweaked are: - Line 9: "124,194,169" = background color. - Line 9: "75.0" = spacing between flowers. - Line 35: "234,236,237" = small flower color. - Line 39: "233,185,185" = larger flower color. - Line 40: "221,218,167" = center circle color for large flowers. Only some combinations of tweaks will work, finding out what works and what doesn't is left as an exercise to the readers. symbols.txt - I took full advantage of nested functions and local scopes in shortening variable names, which means any single character variable means different things on average, depending on which part of the source you are looking at. This file shows a partial mapping for short names to original names. It's unlikely to help at all in understanding how the Kazari works, it's just interesting to know how badly overloaded the variables are. test.pl - verifies that the output from kazari*.ml is pixel-identical to the original implementation. This was used during development to verify that all source code transformations were correct. "make test" will run this script. tiletest.pl - given a JPG or PNG on stdin, this script will produce a HTML file that uses the input image as a tiled background. This is used to verify that output from Kazari tiles properly. Makefile - works just like other makefiles. What's special this time is that I didn't have a MSVC-specific or Windows-specific makefile -- I think it's finally time I ditched my old copy of MSVC, especially since Cygwin+MingW seems every bit better these days. ---------------------------------------------------------------------- 5. Finally... Functional programming is great! Railgun is great! -- omoikane@uguu.org - http://uguu.org/