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 <float.h>
|
||||||
#include "clip.h"
|
#include "clip.h"
|
||||||
|
#include "../containers/aligned_vector.h"
|
||||||
|
|
||||||
ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, float* vout, float* t) {
|
ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, float* vout, float* t) {
|
||||||
if(v1[2] < dist && v2[2] < dist) {
|
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;
|
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
|
#ifndef CLIP_H
|
||||||
#define CLIP_H
|
#define CLIP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "../containers/aligned_vector.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,8 +17,34 @@ typedef enum {
|
||||||
CLIP_RESULT_BACK_TO_FRONT
|
CLIP_RESULT_BACK_TO_FRONT
|
||||||
} ClipResult;
|
} 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);
|
ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, float* vout, float* t);
|
||||||
|
|
||||||
|
|
||||||
|
void clipTriangleStrip(AlignedVector* vertices, AlignedVector* outBuffer);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
static void swapVertex(ClipVertex* v1, ClipVertex* v2) {
|
||||||
|
@ -317,6 +298,27 @@ static void transform(AlignedVector* vertices) {
|
||||||
|
|
||||||
static void clip(AlignedVector* vertices) {
|
static void clip(AlignedVector* vertices) {
|
||||||
/* Perform clipping, generating new vertices as necessary */
|
/* 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) {
|
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]);
|
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);
|
generate(buffer, mode, first, count, (GLubyte*) indices, type, vptr, vstride, cptr, cstride, uvptr, uvstride, nptr, nstride);
|
||||||
light(buffer);
|
light(buffer);
|
||||||
transform(buffer);
|
transform(buffer);
|
||||||
|
clip(buffer);
|
||||||
divide(buffer);
|
divide(buffer);
|
||||||
|
|
||||||
push(buffer, activePolyList());
|
push(buffer, activePolyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user