~zjm/Moon3D

b3467c660ae0cba3c4f5d5aad0cc1784c2530e7c — Zack Michener a month ago b587e37
fix issues with clipping
3 files changed, 129 insertions(+), 22 deletions(-)

M Rendering Meshes.md
M src/everything.h
M src/game.c
M Rendering Meshes.md => Rendering Meshes.md +5 -1
@@ 58,7 58,7 @@ Rendering a mesh follows this process:

1. Copy and transform all of the mesh's vertices into the renderable pool. A
   modeling transformation and perpective projection is done in this step.
2. Copy and clip all of the mesh's faces into the renderable pool. This may add
2. Copy and clip all of the mesh's faces into the renderable pool.† This may add
   new vertices and v-indices, or remove v-indices. A backface-cull check is done
   to avoid unnecessary copying and clipping.
3. Divide each vertex by W and map into device coordinates.


@@ 68,3 68,7 @@ Because vertices and polygons are contiguous in memory and processed all at
once, this algorithm should be cache-efficient. Because only one copy of a
mesh's data is made and continuously updated, it should be space-efficient. Time
efficienty depends on optimization of each step.

†Since the Sutherland-Hodgeman polygon clip algorithm makes several passes over
a polygon, we need to copy it several times. We use a second polygon pool to
copy back and forth between to avoid filling the primary pool.

M src/everything.h => src/everything.h +1 -0
@@ 92,6 92,7 @@ typedef struct Renderer {
	Transform deviceTransform;
	Vertex *vertex_pool;
	int *polygon_pool;
	int *alt_polygon_pool;
	ClipPlanes clip_planes;
} Renderer;


M src/game.c => src/game.c +123 -21
@@ 301,6 301,7 @@ Renderer *NewRenderer(Pixel *pixels, int width, int height)

	r->vertex_pool = NewVertexPool();
	r->polygon_pool = NewPolygonPool();
	r->alt_polygon_pool = NewPolygonPool();

	/* planes in W-space */
	r->clip_planes.x_neg = Pl(V4D(0, 0, 0, 0), V4D(-1,  0,  0, -1));


@@ 429,7 430,7 @@ void Render(Renderable renderable, Transform position, Renderer *renderer)
	for (i = 0, polygon = renderable.mesh->faces;
		 i < renderable.mesh->numFaces;
		 i++, polygon += (*polygon) + 1) {
		ClipPolygon(polygon, renderable.mesh, renderer);
		ClipPolygon(polygon, &renderMesh, renderer);
		renderMesh.numFaces++;
	}



@@ 459,38 460,53 @@ void ProjectVertex(Vertex *vertex, Renderer *renderer)

void ClipPolygon(int *polygon, Mesh *mesh, Renderer *renderer)
{
	ClipPolygonPlane(polygon, mesh, renderer->clip_planes.x_neg, renderer->vertex_pool);
	ClipPolygonPlane(polygon, mesh, renderer->clip_planes.x_pos, renderer->vertex_pool);
	ClipPolygonPlane(polygon, mesh, renderer->clip_planes.y_neg, renderer->vertex_pool);
	ClipPolygonPlane(polygon, mesh, renderer->clip_planes.y_pos, renderer->vertex_pool);
	ClipPolygonPlane(polygon, mesh, renderer->clip_planes.z_neg, renderer->vertex_pool);
	ClipPolygonPlane(polygon, mesh, renderer->clip_planes.z_pos, renderer->vertex_pool);
	int *polygonA = NewPolygon(renderer->polygon_pool);
	int *polygonB = NewPolygon(renderer->alt_polygon_pool);

	ClipPolygonPlane(polygon,  polygonB, mesh, renderer->clip_planes.x_neg, renderer->vertex_pool, renderer->polygon_pool);
	ClipPolygonPlane(polygonB, polygonA, mesh, renderer->clip_planes.x_pos, renderer->vertex_pool, renderer->polygon_pool);
	ClearPolygon(polygonB, renderer->alt_polygon_pool);
	ClipPolygonPlane(polygonA, polygonB, mesh, renderer->clip_planes.y_neg, renderer->vertex_pool, renderer->polygon_pool);
	ClearPolygon(polygonA, renderer->polygon_pool);
	ClipPolygonPlane(polygonB, polygonA, mesh, renderer->clip_planes.y_pos, renderer->vertex_pool, renderer->polygon_pool);
	ClearPolygon(polygonB, renderer->alt_polygon_pool);
	ClipPolygonPlane(polygonA, polygonB, mesh, renderer->clip_planes.z_neg, renderer->vertex_pool, renderer->polygon_pool);
	ClearPolygon(polygonA, renderer->polygon_pool);
	ClipPolygonPlane(polygonB, polygonA, mesh, renderer->clip_planes.z_pos, renderer->vertex_pool, renderer->polygon_pool);
	// clipped polygon is in polygonA
}

void ClipPolygonPlane(int *polygon, Mesh *mesh, Plane clipBoundary, Vertex *vertex_pool)
int *NewPolygon(int *pool)
{
	Vertex *newCurrent, *intersection, *current, *previous;
	assert(PoolTotal(pool) < MAX_RENDER_POLYGONS);
	int *polygon = PoolNext(pool);
	*polygon = 0;
	return polygon;
}

	if (NumPolygonVertices(polygon) == 0) return;
void ClipPolygonPlane(int *srcPolygon, int *dstPolygon, Mesh *mesh, Plane clipBoundary, Vertex *vertex_pool, int *polygon_pool)
{
	Vertex *intersection, *current, *previous;

	previous = LastPolygonVertex(polygon, mesh->vertices);
	for (int i = 0; i < NumPolygonVertices(polygon); i++) {
		current = PolygonVertex(polygon, mesh->vertices, i);
	if (NumPolygonVertices(srcPolygon) == 0) return;

	previous = LastPolygonVertex(srcPolygon, mesh->vertices);
	for (int i = 0; i < NumPolygonVertices(srcPolygon); i++) {
		current = PolygonVertex(srcPolygon, mesh->vertices, i);
		if (VertexInside(current, clipBoundary)) {
			if (VertexInside(previous, clipBoundary)) {
				newCurrent = NewVertex(vertex_pool);
				*newCurrent = *current;
				mesh->numVertices++;
				AddPolygonValue(dstPolygon, polygon_pool, PolygonValue(srcPolygon, i));
			} else {
				intersection = NewVertex(vertex_pool);
				*intersection = ClipIntersect(previous, current, clipBoundary);
				newCurrent = NewVertex(vertex_pool);
				*newCurrent = *current;
				AddPolygonValue(dstPolygon, polygon_pool, mesh->numVertices++);
				AddPolygonValue(dstPolygon, polygon_pool, PolygonValue(srcPolygon, i));
			}
		} else {
			if (VertexInside(previous, clipBoundary)) {
				intersection = NewVertex(vertex_pool);
				*intersection = ClipIntersect(previous, current, clipBoundary);
				AddPolygonValue(dstPolygon, polygon_pool, mesh->numVertices++);
			}
		}
		previous = current;


@@ 524,13 540,99 @@ void WireframePolygon(int *polygon, Vertex *vertices, Renderer *renderer)
	previous = LastPolygonVertex(polygon, vertices);
	for (int i = 0; i < NumPolygonVertices(polygon); i++) {
		current = PolygonVertex(polygon, vertices, i);
		RasterLine(previous, current, WHITE, renderer);
		RasterLine(*previous, *current, WHITE, renderer);
	}
}

void RasterLine(Vertex *a, Vertex *b, Color color, Renderer *renderer)
void RasterLine(Vertex a, Vertex b, Color color, Renderer *renderer)
{
	// TODO
	double dx = b.x - a.x;
	double dy = b.y - a.y;
	if (fabs(dy) < fabs(dx)) {
		if (a.x > b.x) {
			RasterLineShallow(b, a, color, renderer);
		} else {
			RasterLineShallow(a, b, color, renderer);
		}
	} else {
		if (a.y > b.y) {
			RasterLineSteep(b, a, color, renderer);
		} else {
			RasterLineSteep(a, b, color, renderer);
		}
	}
}

void RasterLineShallow(Vertex a, Vertex b, Color color, Renderer *renderer)
{
	double dx = b.x - a.x;
	double dy = b.y - a.y;
	double yi = 1;
	if (dy < 0) {
		yi = -1;
		dy = -dy;
	}

	double d = 2*dy - dx;
	double x;
	double y = a.y;

	for (x = a.x; x <= b.x; x++) {
		double z = MapRange(x, a.x, b.x, a.z, b.z);
		if (UpdateDepthBuffer(x, y, z, renderer)) {
			WritePixel(x, y, color, renderer);
		}
		if (d > 0) {
			y += yi;
			d -= 2*dx;
		}
		d += 2*dy;
	}
}

void RasterLineSteep(Vertex a, Vertex b, Color color, Renderer *renderer)
{
	double dx = b.x - a.x;
	double dy = b.y - a.y;
	double xi = 1;
	if (dx < 0) {
		xi = -1;
		dx = -dx;
	}

	double d = 2*dx - dy;
	double x = a.x;
	double y;

	for (y = a.y; y <= b.y; y++) {
		double z = MapRange(y, a.y, b.y, a.z, b.z);
		if (UpdateDepthBuffer(x, y, z, renderer)) {
			WritePixel(x, y, color, renderer);
		}
		if (d > 0) {
			x += xi;
			d -= 2*dy;
		}
		d += 2*dx;
	}
}

void WritePixel(int x, int y, Color color, Renderer *renderer)
{
	Pixel p = ColorPixel(color);
	if (x >= 0 && x < renderer->width && y >= 0 && y < renderer->height) {
		renderer->pixels[(renderer->height - 1 - y)*renderer->width+x] = p;
	}
}

bool UpdateDepthBuffer(int x, int y, double z, Renderer *renderer)
{
	if (z > renderer->depthBuffer[y*renderer->width+x]) {
		renderer->depthBuffer[y*renderer->width+x] = z;
		return true;
	} else {
		return false;
	}
}

void RenderParticle(Particle particle, Renderer *renderer)