Implement z clipping for the single-vertex case
This commit is contained in:
parent
ab13ed4747
commit
5387734e6c
163
GL/clip.c
163
GL/clip.c
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
30
GL/clip.h
30
GL/clip.h
|
@ -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
|
||||
|
|
44
GL/draw.c
44
GL/draw.c
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user