Add inverse z-buffering
This commit is contained in:
		
							parent
							
								
									63e8bd1b93
								
							
						
					
					
						commit
						8ede3f1952
					
				
							
								
								
									
										3
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										3
									
								
								Makefile
								
								
								
								
							| 
						 | 
				
			
			@ -31,7 +31,8 @@ CC=clang++
 | 
			
		|||
WARNINGS_ON=-Weverything
 | 
			
		||||
WARNINGS_OFF=-Wno-missing-braces -Wno-gnu-anonymous-struct -Wno-old-style-cast\
 | 
			
		||||
			 -Wno-zero-as-null-pointer-constant -Wno-nested-anon-types\
 | 
			
		||||
			 -Wno-padded -Wno-exit-time-destructors -Wno-global-constructors
 | 
			
		||||
			 -Wno-padded -Wno-exit-time-destructors -Wno-global-constructors\
 | 
			
		||||
			 -Wno-c++98-compat
 | 
			
		||||
 | 
			
		||||
CFLAGS=$(D) $(O) -std=c++11 $(WARNINGS_ON) $(WARNINGS_OFF) -I$(INCLUDE_DIR)
 | 
			
		||||
LIBS=-lSDL2
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,7 +26,8 @@ enum Engine_Input
 | 
			
		|||
// STRUCTURES
 | 
			
		||||
struct Engine_Buffer
 | 
			
		||||
{
 | 
			
		||||
    uint32_t *pixels;
 | 
			
		||||
    uint32_t *buffer;
 | 
			
		||||
    float *zbuffer;
 | 
			
		||||
    int width;
 | 
			
		||||
    int height;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -77,10 +77,11 @@ struct Mesh
 | 
			
		|||
 | 
			
		||||
// PUBLIC FUNCTIONS
 | 
			
		||||
void FillTriangle(
 | 
			
		||||
        uint32_t *buffer, int width, uint32_t color,
 | 
			
		||||
        float x0, float y0,
 | 
			
		||||
        float x1, float y1,
 | 
			
		||||
        float x2, float y2);
 | 
			
		||||
        uint32_t *buffer, int width,
 | 
			
		||||
        float *zbuffer, uint32_t color,
 | 
			
		||||
        float x0, float y0, float z0,
 | 
			
		||||
        float x1, float y1, float z1,
 | 
			
		||||
        float x2, float y2, float z2);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define GEOMETRY_H
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,6 +74,13 @@ inline Point operator*(Point v, Matrix m)
 | 
			
		|||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline Point &operator*=(Point &v, Matrix m)
 | 
			
		||||
{
 | 
			
		||||
    v = v * m;
 | 
			
		||||
 | 
			
		||||
    return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define MATRIX_H
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -36,6 +36,14 @@ inline Point operator/(Point v, float f)
 | 
			
		|||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// v /= f
 | 
			
		||||
inline Point &operator/=(Point &v, float f)
 | 
			
		||||
{
 | 
			
		||||
    v = v / f;
 | 
			
		||||
 | 
			
		||||
    return v;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// v1 - v2
 | 
			
		||||
inline Vector operator-(Point v1, Point v2)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@
 | 
			
		|||
#include "transform.h"
 | 
			
		||||
#include "util.h"
 | 
			
		||||
#include "vec.h"
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// GLOBALS
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +50,8 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
 | 
			
		|||
{
 | 
			
		||||
    CheckInputs(input);
 | 
			
		||||
 | 
			
		||||
    unsigned long bufferSize = (unsigned long)(buffer.width * buffer.height);
 | 
			
		||||
    memset(buffer.zbuffer, 0, bufferSize * sizeof(float));
 | 
			
		||||
 | 
			
		||||
    // Local space to world space
 | 
			
		||||
    Matrix tTranslate = Transform_Translate(
 | 
			
		||||
| 
						 | 
				
			
			@ -62,8 +64,7 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
 | 
			
		|||
 | 
			
		||||
    for (size_t v = 0; v < mesh.verts.size(); ++v)
 | 
			
		||||
    {
 | 
			
		||||
        mesh.vertsTransformed[v] =
 | 
			
		||||
            mesh.verts[v] * tScale * tRotate * tTranslate;
 | 
			
		||||
        mesh.vertsTransformed[v] = mesh.verts[v] * tScale * tRotate * tTranslate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -99,25 +100,17 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
 | 
			
		|||
    // World space to camera (view) space
 | 
			
		||||
    Matrix tView = Transform_View(camera.position, camera.rotation);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Camera space to perspective
 | 
			
		||||
    Matrix tPersp = Transform_Perspective(
 | 
			
		||||
            camera.xZoom, camera.yZoom, camera.nearClip, camera.farClip);
 | 
			
		||||
 | 
			
		||||
    for (size_t v = 0; v < mesh.verts.size(); ++v)
 | 
			
		||||
    {
 | 
			
		||||
        mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tView * tPersp;
 | 
			
		||||
 | 
			
		||||
        mesh.vertsTransformed[v] =
 | 
			
		||||
            mesh.vertsTransformed[v] / mesh.vertsTransformed[v].w;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Perspective to screen
 | 
			
		||||
    Matrix tScreen = Transform_Screen(camera.xScale, camera.yScale);
 | 
			
		||||
 | 
			
		||||
    for (size_t v = 0; v < mesh.verts.size(); ++v)
 | 
			
		||||
    {
 | 
			
		||||
        mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tScreen;
 | 
			
		||||
        mesh.vertsTransformed[v] *= tView * tPersp * tScreen;
 | 
			
		||||
        mesh.vertsTransformed[v] /= mesh.vertsTransformed[v].w;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -129,10 +122,11 @@ void Engine_Render(Engine_Buffer &buffer, uint32_t input)
 | 
			
		|||
        unsigned int v2 = mesh.culledFaces[f].vertIndex[2];
 | 
			
		||||
 | 
			
		||||
        FillTriangle(
 | 
			
		||||
                buffer.pixels, buffer.width, mesh.faces[f].color.u32,
 | 
			
		||||
                mesh.vertsTransformed[v0].x, mesh.vertsTransformed[v0].y,
 | 
			
		||||
                mesh.vertsTransformed[v1].x, mesh.vertsTransformed[v1].y,
 | 
			
		||||
                mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y);
 | 
			
		||||
                buffer.buffer, buffer.width,
 | 
			
		||||
                buffer.zbuffer, mesh.faces[f].color.u32,
 | 
			
		||||
                mesh.vertsTransformed[v0].x, mesh.vertsTransformed[v0].y, mesh.vertsTransformed[v0].z,
 | 
			
		||||
                mesh.vertsTransformed[v1].x, mesh.vertsTransformed[v1].y, mesh.vertsTransformed[v1].z,
 | 
			
		||||
                mesh.vertsTransformed[v2].x, mesh.vertsTransformed[v2].y, mesh.vertsTransformed[v2].z);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										114
									
								
								src/geometry.cpp
								
								
								
								
							
							
						
						
									
										114
									
								
								src/geometry.cpp
								
								
								
								
							| 
						 | 
				
			
			@ -12,24 +12,27 @@
 | 
			
		|||
 | 
			
		||||
// PRIVATE PROTOTYPES
 | 
			
		||||
static void FillTriangleFlatBottom(
 | 
			
		||||
        uint32_t *buffer, int width, uint32_t color,
 | 
			
		||||
        float x0, float y0,
 | 
			
		||||
        float x1, float y1,
 | 
			
		||||
        float x2, float y2);
 | 
			
		||||
        uint32_t *buffer, int width,
 | 
			
		||||
        float *zbuffer, uint32_t color,
 | 
			
		||||
        float x0, float y0, float z0,
 | 
			
		||||
        float x1, float y1, float z1,
 | 
			
		||||
        float x2, float y2, float z2);
 | 
			
		||||
 | 
			
		||||
static void FillTriangleFlatTop(
 | 
			
		||||
        uint32_t *buffer, int width, uint32_t color,
 | 
			
		||||
        float x0, float y0,
 | 
			
		||||
        float x1, float y1,
 | 
			
		||||
        float x2, float y2);
 | 
			
		||||
        uint32_t *buffer, int width,
 | 
			
		||||
        float *zbuffer, uint32_t color,
 | 
			
		||||
        float x0, float y0, float z0,
 | 
			
		||||
        float x1, float y1, float z1,
 | 
			
		||||
        float x2, float y2, float z2);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// PUBLIC FUNCTIONS
 | 
			
		||||
void FillTriangle(
 | 
			
		||||
        uint32_t *buffer, int width, uint32_t color,
 | 
			
		||||
        float x0, float y0,
 | 
			
		||||
        float x1, float y1,
 | 
			
		||||
        float x2, float y2)
 | 
			
		||||
        uint32_t *buffer, int width,
 | 
			
		||||
        float *zbuffer, uint32_t color,
 | 
			
		||||
        float x0, float y0, float z0,
 | 
			
		||||
        float x1, float y1, float z1,
 | 
			
		||||
        float x2, float y2, float z2)
 | 
			
		||||
{
 | 
			
		||||
    // Horizontal or vertical
 | 
			
		||||
    if ((FLOAT_EQUAL(x0,x1) && FLOAT_EQUAL(x1, x2))
 | 
			
		||||
| 
						 | 
				
			
			@ -44,31 +47,34 @@ void FillTriangle(
 | 
			
		|||
    {
 | 
			
		||||
        SWAP(x0, x1, temp);
 | 
			
		||||
        SWAP(y0, y1, temp);
 | 
			
		||||
        SWAP(z0, z1, temp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (y0 > y2)
 | 
			
		||||
    {
 | 
			
		||||
        SWAP(x0, x2, temp);
 | 
			
		||||
        SWAP(y0, y2, temp);
 | 
			
		||||
        SWAP(z0, z2, temp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (y1 > y2)
 | 
			
		||||
    {
 | 
			
		||||
        SWAP(x1, x2, temp);
 | 
			
		||||
        SWAP(y1, y2, temp);
 | 
			
		||||
        SWAP(z1, z2, temp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Flat top triangle
 | 
			
		||||
    if (FLOAT_EQUAL(y0, y1))
 | 
			
		||||
    {
 | 
			
		||||
        FillTriangleFlatTop(buffer, width, color, x0, y0, x1, y1, x2, y2);
 | 
			
		||||
        FillTriangleFlatTop(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x2, y2, z2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Flat bottom triangle
 | 
			
		||||
    else if (FLOAT_EQUAL(y1, y2))
 | 
			
		||||
    {
 | 
			
		||||
        FillTriangleFlatBottom(buffer, width, color, x0, y0, x1, y1, x2, y2);
 | 
			
		||||
        FillTriangleFlatBottom(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x2, y2, z2);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Other - decompose into two triangles
 | 
			
		||||
| 
						 | 
				
			
			@ -78,27 +84,30 @@ void FillTriangle(
 | 
			
		|||
        // New y is the same as y1
 | 
			
		||||
        float x3 = x0 + (((y1 - y0) / (y2 - y0)) * (x2 - x0));
 | 
			
		||||
        float y3 = y1;
 | 
			
		||||
        float z3 = z1;
 | 
			
		||||
 | 
			
		||||
        FillTriangleFlatBottom(buffer, width, color, x0, y0, x1, y1, x3, y3);
 | 
			
		||||
        FillTriangleFlatTop(buffer, width, color, x1, y1, x3, y3, x2, y2);
 | 
			
		||||
        FillTriangleFlatBottom(buffer, width, zbuffer, color, x0, y0, z0, x1, y1, z1, x3, y3, z3);
 | 
			
		||||
        FillTriangleFlatTop(buffer, width, zbuffer, color, x1, y1, z1, x3, y3, z3, x2, y2, z2);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// PRIVATE FUNCTIONS
 | 
			
		||||
static void FillTriangleFlatBottom(
 | 
			
		||||
        uint32_t *buffer, int width, uint32_t color,
 | 
			
		||||
        float x0, float y0,
 | 
			
		||||
        float x1, float y1,
 | 
			
		||||
        float x2, float y2)
 | 
			
		||||
        uint32_t *buffer, int width,
 | 
			
		||||
        float *zbuffer, uint32_t color,
 | 
			
		||||
        float x0, float y0, float z0,
 | 
			
		||||
        float x1, float y1, float z1,
 | 
			
		||||
        float x2, float y2, float z2)
 | 
			
		||||
{
 | 
			
		||||
    if (x2 < x1)
 | 
			
		||||
    {
 | 
			
		||||
        float temp;
 | 
			
		||||
        SWAP(x1, x2, temp);
 | 
			
		||||
        SWAP(x2, x1, temp);
 | 
			
		||||
        SWAP(y2, y1, temp);
 | 
			
		||||
        SWAP(z2, z1, temp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Top-left fill convention
 | 
			
		||||
    float dxdy_left = (x1 - x0) / (y1 - y0);
 | 
			
		||||
    float dxdy_right = (x2 - x0) / (y2 - y0);
 | 
			
		||||
| 
						 | 
				
			
			@ -108,35 +117,62 @@ static void FillTriangleFlatBottom(
 | 
			
		|||
    float xEnd = x0 + dxdy_right * (yStart - y0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Inverse z-buffering
 | 
			
		||||
    float z0Inv = 1.0f / z0;
 | 
			
		||||
    float z1Inv = 1.0f / z1;
 | 
			
		||||
    float z2Inv = 1.0f / z2;
 | 
			
		||||
    float dzdy_left = (z1Inv - z0Inv) / (y1 - y0);
 | 
			
		||||
    float dzdy_right = (z2Inv - z0Inv) / (y2 - y0);
 | 
			
		||||
    float zStart = z0Inv;
 | 
			
		||||
    float zEnd = z0Inv;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Fill
 | 
			
		||||
    for (int y = yStart; y <= yEnd; ++y)
 | 
			
		||||
    {
 | 
			
		||||
        float dzdx = (zEnd - zStart) / (xEnd - xStart);
 | 
			
		||||
        float z = zStart;
 | 
			
		||||
 | 
			
		||||
        int xStartInt = (int)xStart;
 | 
			
		||||
        int xEndInt = (int)xEnd;
 | 
			
		||||
 | 
			
		||||
        for (int x = xStartInt; x <= xEndInt; ++x)
 | 
			
		||||
        {
 | 
			
		||||
            int pixel = (y * width) + x;
 | 
			
		||||
 | 
			
		||||
            if (z > zbuffer[pixel])
 | 
			
		||||
            {
 | 
			
		||||
                DrawPixel(buffer, width, color, x, y);
 | 
			
		||||
 | 
			
		||||
                zbuffer[pixel] = z;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            z += dzdx;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        xStart += dxdy_left;
 | 
			
		||||
        xEnd += dxdy_right;
 | 
			
		||||
 | 
			
		||||
        zStart += dzdy_left;
 | 
			
		||||
        zEnd += dzdy_right;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void FillTriangleFlatTop(
 | 
			
		||||
        uint32_t *buffer, int width, uint32_t color,
 | 
			
		||||
        float x0, float y0,
 | 
			
		||||
        float x1, float y1,
 | 
			
		||||
        float x2, float y2)
 | 
			
		||||
        uint32_t *buffer, int width,
 | 
			
		||||
        float *zbuffer, uint32_t color,
 | 
			
		||||
        float x0, float y0, float z0,
 | 
			
		||||
        float x1, float y1, float z1,
 | 
			
		||||
        float x2, float y2, float z2)
 | 
			
		||||
{
 | 
			
		||||
    if (x1 < x0)
 | 
			
		||||
    {
 | 
			
		||||
        float temp;
 | 
			
		||||
        SWAP(x1, x0, temp);
 | 
			
		||||
        SWAP(y1, y0, temp);
 | 
			
		||||
        SWAP(z1, z0, temp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Top-left fill convention
 | 
			
		||||
    float dxdy_left = (x2 - x0) / (y2 - y0);
 | 
			
		||||
    float dxdy_right = (x2 - x1) / (y2 - y1);
 | 
			
		||||
| 
						 | 
				
			
			@ -146,19 +182,43 @@ static void FillTriangleFlatTop(
 | 
			
		|||
    float xEnd = x1 + dxdy_right * (yStart - y0);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Inverse z-buffering
 | 
			
		||||
    float z0Inv = 1.0f / z0;
 | 
			
		||||
    float z1Inv = 1.0f / z1;
 | 
			
		||||
    float z2Inv = 1.0f / z2;
 | 
			
		||||
    float dzdy_left = (z2Inv - z0Inv) / (y2 - y0);
 | 
			
		||||
    float dzdy_right = (z2Inv - z1Inv) / (y2 - y1);
 | 
			
		||||
    float zStart = z0Inv;
 | 
			
		||||
    float zEnd = z1Inv;
 | 
			
		||||
 | 
			
		||||
    // Fill
 | 
			
		||||
    for (int y = yStart; y <= yEnd; ++y)
 | 
			
		||||
    {
 | 
			
		||||
        float dzdx = (zEnd - zStart) / (xEnd - xStart);
 | 
			
		||||
        float z = zStart;
 | 
			
		||||
 | 
			
		||||
        int xStartInt = (int)xStart;
 | 
			
		||||
        int xEndInt = (int)xEnd;
 | 
			
		||||
 | 
			
		||||
        for (int x = xStartInt; x <= xEndInt; ++x)
 | 
			
		||||
        {
 | 
			
		||||
            int pixel = (y * width) + x;
 | 
			
		||||
 | 
			
		||||
            if (z > zbuffer[pixel])
 | 
			
		||||
            {
 | 
			
		||||
                DrawPixel(buffer, width, color, x, y);
 | 
			
		||||
 | 
			
		||||
                zbuffer[pixel] = z;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            z += dzdx;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        xStart += dxdy_left;
 | 
			
		||||
        xEnd += dxdy_right;
 | 
			
		||||
 | 
			
		||||
        zStart += dzdy_left;
 | 
			
		||||
        zEnd += dzdy_right;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,7 +29,8 @@ int main(int argc, char *argv[])
 | 
			
		|||
    if (result == PLATFORM_OK)
 | 
			
		||||
    {
 | 
			
		||||
        Engine_Buffer buffer = {};
 | 
			
		||||
        buffer.pixels = (uint32_t*)platform.surface->pixels;
 | 
			
		||||
        buffer.buffer = (uint32_t*)platform.surface->pixels;
 | 
			
		||||
        buffer.zbuffer = (float*)calloc((size_t)(platform.surface->w * platform.surface->h), sizeof(float));
 | 
			
		||||
        buffer.width = platform.surface->w;
 | 
			
		||||
        buffer.height = platform.surface->h;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue