Maybe this will turn out to be a premature postmortem blog, but at least my Jani Frequency pretty low since I don't write that often. Well, in this moment, I believe I will shelf the project. Might dig it up for a micro jam-game or something. Or take if off the shelf I mean. Anyhow.
It's about the software renderer I started for Goofy4Digits. I was thinking I could do something else with it after the compo, but now I'm dropping it. I decided I should blog about it. Droppin'n'Bloggin. If you count only the code-base, the project started with the compo, but I've been interested in software rendering for a long time and experimented with it now and then since last year. I've been itching to write a renderer in C.I decided to not use floats. Not <math.h> either because it uses floats. I wanted to play around with integers and bit fiddling, I seldom get to do that. And it would be more true to the retro vibe. A lot of stuff like this:
But this is not a real deal DOS game or anything. I use win32 + openGL for scaling up the framebuffer to fullscreen. 320x200 gets annoyingly small on a modern display. Nor am I using asm, which would probably be necessary for making it fast enough for a 90s PC. ^ Exquisite texture work.The greffix pipeline goes like this1. Have a triangle, three vertices of some kind. {x,y,z, u,v, r,g,b}2. Transform verts by inverse camera matrix, do lighting calcs per vertex.3. Clip triangle by frustum planes.4. Perspective divide.4.5 (optional) Store primitive (type info, texture id, verts) in a z-ordered list and draw later.5.a Rasterize. It's different from the method I used in MAG64 where I tested each pixel inside the rectangleformed around the triangle. This time the triangle edges are traced, and for each scan line, you get two new vertices which are mixed versions of the top and bottom verts on each edge. For perspective correctness, their depth difference must be taken into account. 5.b The same thing goes on each pixel on the scan line (between the two new verts), t must be adjusted.
I'm not going to write more detailed than this. I'll upload the src to github if anyone is interested.Features 16-bit color framebuffer, RGBA_5551. The alpha bit is used as a mask when drawing the "sky-box". PS1-style matrix dithering. 4 function shading modes: Solid color. The fastest. Gouraud. Interpolate colors between vertices in linearly 2D. Perspective correct Gouraud. Interpolate colors between vertices, with regards to depth of each vertex. Perspective correct Gouraud Textured. As above, but with texture sampling. (With only one hard coded texture available to choose from and no system for multiple texture of any sort.) Oh god, oh god, I spent a month on this??? This could have been made in Unity in one hour. But, I'm not feeling too bad. I've spent a good time of the evenings and weekends away from the computer enjoying the summer. :)It would've been possible to take one or two days and just make a goofy little game like a simple space shooter or frogger or something by the end of the compo. The engine was good enough at that point (terrible, but capable). Tho, I'd risk that feared second place.I'm feeling pretty happy about leaving this thing now. I've done enough to see what the fuzz is about, I can happily go back to more practical things. Like gl. Or maybe something entirely different. I'm a little sick of programming atm. Maybe do more art. Or watch watch 700 episodes of One Piece. (YOU decide in the comments!!)Inspiration: Mechwarrior 2, Star Fox, Doom, and the usual PS1 stuff.
//let 4096 (or 1<<12) represent 1.0
//a * b would be
a * b >> 12
//for division
(a << 12 ) / b
//PSUEDO, pretend everything is float for readability
//how far we've come on the scanline between two verts
t = current_pixel / (end - start); // unadjusted, some number between 0. and 1.
//divide t on both sides of the pixel by z
w0 = (1.-t) / A.z;
w1 = t / B.z;
//normalize
t = w1 / ( w0 + w1 );
//depth correct interpolated vertex values ( uv's, rgb's)
vertex = interpolate ( A, B, t );
//our "shader program"
framebuffer[ current pixel ] = sample_texture( vertex.s, vertex.t );
I suddenly feel like trying this myself again, just for the fun of it. :D