Implement z clipping for the single-vertex case

This commit is contained in:
Luke Benstead 2018-07-10 19:48:25 +01:00
parent ab13ed4747
commit 5387734e6c
3 changed files with 216 additions and 21 deletions

163
GL/clip.c
View File

@ -1,5 +1,6 @@
#include <float.h>
#include "clip.h"
#include "../containers/aligned_vector.h"
ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, float* vout, float* t) {
if(v1[2] < dist && v2[2] < dist) {
@ -32,3 +33,165 @@ ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, f
return CLIP_RESULT_ALL_ON_PLANE;
}
}
static void interpolateVec2(const float* v1, const float* v2, const float t, float* out) {
/* FIXME: SH4 has an asm instruction for this */
out[0] = v1[0] + (v2[0] - v1[0]) * t;
out[1] = v1[1] + (v2[1] - v1[1]) * t;
}
static void interpolateVec3(const float* v1, const float* v2, const float t, float* out) {
/* FIXME: SH4 has an asm instruction for this */
out[0] = v1[0] + (v2[0] - v1[0]) * t;
out[1] = v1[1] + (v2[1] - v1[1]) * t;
out[2] = v1[2] + (v2[2] - v1[2]) * t;
}
static void interpolateColour(const uint32_t* c1, const uint32_t* c2, const float t, const uint32_t* out) {
/* FIXME: Needs float casting stuff to actually work */
}
const uint32_t VERTEX_CMD_EOL = 0xf0000000;
const uint32_t VERTEX_CMD = 0xe0000000;
void clipTriangleStrip(AlignedVector* vertices, AlignedVector* outBuffer) {
/* Clipping triangle strips is *hard* this is the algorithm we follow:
*
* - Treat each triangle in the strip individually.
* - If we find a triangle that needs clipping, treat it in isolation.
* - End the strip at the triangle
* - Generate a new single-triangle strip for it
* - Begin a new strip for the remainder of the strip
*
* There is probably more efficient way but there are so many different cases to handle that it's
* difficult to even write them down!
*/
uint32_t i;
for(i = 2; i < vertices->size; ++i) {
ClipVertex* sourceTriangle[3] = {
aligned_vector_at(vertices, i - 2),
aligned_vector_at(vertices, i - 1),
aligned_vector_at(vertices, i)
};
ClipVertex* v1 = sourceTriangle[0];
ClipVertex* v2 = sourceTriangle[1];
ClipVertex* v3 = sourceTriangle[2];
uint8_t visible = ((v1->xyz[2] <= 0) ? 4 : 0) | ((v2->xyz[2] <= 0) ? 2 : 0) | ((v3->xyz[2] <= 0) ? 1 : 0);
/* All visible, we're fine! */
if(visible == 0b111) {
if(i == 2) {
aligned_vector_push_back(outBuffer, v1, 1);
aligned_vector_push_back(outBuffer, v2, 1);
}
aligned_vector_push_back(outBuffer, v3, 1);
} else if(visible == 0b000) {
/* Do nothing */
continue;
} else if(visible == 0b100) {
} else if(visible == 0b010) {
} else if(visible == 0b001) {
} else if(visible == 0b110) {
/* Third vertex isn't visible */
float t1 = 0, t2 = 0;
ClipVertex output[4];
/* FIXME: Interpolate other values (colors etc.) */
clipLineToNearZ(v2->xyz, v3->xyz, 0, output[2].xyz, &t1);
clipLineToNearZ(v1->xyz, v3->xyz, 0, output[3].xyz, &t2);
output[0] = *v1;
output[1] = *v2;
/* Interpolate normals */
interpolateVec3(v2->nxyz, v3->nxyz, t1, output[2].nxyz);
interpolateVec3(v1->nxyz, v3->nxyz, t2, output[3].nxyz);
/* Interpolate texcoords */
interpolateVec2(v2->uv, v3->uv, t1, output[2].uv);
interpolateVec2(v1->uv, v3->uv, t2, output[3].uv);
interpolateColour((uint32_t*) &v2->argb, (uint32_t*) &v3->argb, t1, (uint32_t*) &output[2].argb);
interpolateColour((uint32_t*) &v1->argb, (uint32_t*) &v3->argb, t2, (uint32_t*) &output[3].argb);
output[0].flags = VERTEX_CMD;
output[1].flags = VERTEX_CMD;
output[2].flags = VERTEX_CMD;
output[3].flags = VERTEX_CMD_EOL;
aligned_vector_push_back(outBuffer, output, 4);
} else if(visible == 0b011) {
/* First vertex isn't visible, so let's clip along the lines to the second and third */
float t1 = 0, t2 = 0;
ClipVertex output[4];
/* FIXME: Interpolate other values (colors etc.) */
clipLineToNearZ(v1->xyz, v2->xyz, 0, output[0].xyz, &t1);
clipLineToNearZ(v1->xyz, v3->xyz, 0, output[2].xyz, &t2);
output[1] = *v2;
output[3] = *v3;
/* Interpolate normals */
interpolateVec3(v1->nxyz, v2->nxyz, t1, output[0].nxyz);
interpolateVec3(v1->nxyz, v3->nxyz, t2, output[2].nxyz);
/* Interpolate texcoords */
interpolateVec2(v1->uv, v2->uv, t1, output[0].uv);
interpolateVec2(v1->uv, v3->uv, t2, output[2].uv);
interpolateColour((uint32_t*) &v1->argb, (uint32_t*) &v2->argb, t1, (uint32_t*) &output[0].argb);
interpolateColour((uint32_t*) &v1->argb, (uint32_t*) &v3->argb, t2, (uint32_t*) &output[2].argb);
output[0].flags = VERTEX_CMD;
output[1].flags = VERTEX_CMD;
output[2].flags = VERTEX_CMD;
output[3].flags = VERTEX_CMD_EOL;
aligned_vector_push_back(outBuffer, output, 4);
} else if(visible == 0b101) {
/* Second vertex isn't visible */
float t1 = 0, t2 = 0;
ClipVertex output[4];
/* FIXME: Interpolate other values (colors etc.) */
clipLineToNearZ(v1->xyz, v2->xyz, 0, output[1].xyz, &t1);
clipLineToNearZ(v3->xyz, v2->xyz, 0, output[2].xyz, &t2);
output[0] = *v1;
output[3] = *v3;
/* Interpolate normals */
interpolateVec3(v1->nxyz, v2->nxyz, t1, output[1].nxyz);
interpolateVec3(v3->nxyz, v2->nxyz, t2, output[2].nxyz);
/* Interpolate texcoords */
interpolateVec2(v1->uv, v2->uv, t1, output[1].uv);
interpolateVec2(v3->uv, v2->uv, t2, output[2].uv);
interpolateColour((uint32_t*) &v1->argb, (uint32_t*) &v2->argb, t1, (uint32_t*) &output[1].argb);
interpolateColour((uint32_t*) &v3->argb, (uint32_t*) &v2->argb, t2, (uint32_t*) &output[2].argb);
output[0].flags = VERTEX_CMD;
output[1].flags = VERTEX_CMD;
output[2].flags = VERTEX_CMD;
output[3].flags = VERTEX_CMD_EOL;
aligned_vector_push_back(outBuffer, output, 4);
}
}
}

View File

@ -1,6 +1,10 @@
#ifndef CLIP_H
#define CLIP_H
#include <stdint.h>
#include "../containers/aligned_vector.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -13,8 +17,34 @@ typedef enum {
CLIP_RESULT_BACK_TO_FRONT
} ClipResult;
typedef struct {
uint8_t a;
uint8_t r;
uint8_t g;
uint8_t b;
} ClipColour;
/* Note: This structure is the almost the same format as pvr_vertex_t aside from the offet
* (oargb) which is replaced by the floating point w value. This is so that we can
* simply zero it and memcpy the lot into the output */
typedef struct {
uint32_t flags;
float xyz[3];
float uv[2];
ClipColour argb;
float nxyz[3];
float w;
float xyzES[3]; /* Coordinate in eye space */
float nES[3]; /* Normal in eye space */
} ClipVertex;
ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, float* vout, float* t);
void clipTriangleStrip(AlignedVector* vertices, AlignedVector* outBuffer);
#ifdef __cplusplus
}
#endif

View File

@ -178,27 +178,8 @@ inline void transformNormalToEyeSpace(GLfloat* normal) {
}
typedef struct {
uint8_t a;
uint8_t r;
uint8_t g;
uint8_t b;
} Colour;
/* Note: This structure is the almost the same format as pvr_vertex_t aside from the offet
* (oargb) which is replaced by the floating point w value. This is so that we can
* simply zero it and memcpy the lot into the output */
typedef struct {
uint32_t flags;
float xyz[3];
float uv[2];
Colour argb;
float nxyz[3];
float w;
float xyzES[3]; /* Coordinate in eye space */
float nES[3]; /* Normal in eye space */
} ClipVertex;
static void swapVertex(ClipVertex* v1, ClipVertex* v2) {
@ -317,6 +298,27 @@ static void transform(AlignedVector* vertices) {
static void clip(AlignedVector* vertices) {
/* Perform clipping, generating new vertices as necessary */
static AlignedVector* CLIP_BUFFER = NULL;
/* First entry into this, allocate the clip buffer */
if(!CLIP_BUFFER) {
CLIP_BUFFER = (AlignedVector*) malloc(sizeof(AlignedVector));
aligned_vector_init(CLIP_BUFFER, sizeof(ClipVertex));
}
/* Make sure we allocate roughly enough space */
aligned_vector_reserve(CLIP_BUFFER, vertices->size);
/* Start from empty */
aligned_vector_resize(CLIP_BUFFER, 0);
/* Now perform clipping! */
clipTriangleStrip(vertices, CLIP_BUFFER);
/* Copy the clip buffer over the vertices */
aligned_vector_resize(vertices, CLIP_BUFFER->size);
memcpy(vertices->data, CLIP_BUFFER->data, CLIP_BUFFER->size * CLIP_BUFFER->element_size);
}
static void mat_transform3(const float* xyz, const float* xyzOut, const uint32_t count, const uint32_t stride) {
@ -385,7 +387,7 @@ static void light(AlignedVector* vertices) {
}
uint32_t final = PVR_PACK_COLOR(contribution[3], contribution[0], contribution[1], contribution[2]);
vertex->argb = *((Colour*) &final);
vertex->argb = *((ClipColour*) &final);
}
}
@ -465,8 +467,8 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
generate(buffer, mode, first, count, (GLubyte*) indices, type, vptr, vstride, cptr, cstride, uvptr, uvstride, nptr, nstride);
light(buffer);
transform(buffer);
clip(buffer);
divide(buffer);
push(buffer, activePolyList());
}