Start working on z-clipping
This commit is contained in:
parent
5b05039dfd
commit
1baeba1c59
66
GL/clip.c
66
GL/clip.c
|
@ -32,3 +32,69 @@ ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, f
|
|||
return CLIP_RESULT_ALL_ON_PLANE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TriangleClipResult clipTriangleToNearZ(
|
||||
const float plane_dist,
|
||||
const unsigned short triangle_n, const pvr_vertex_t* v1, const pvr_vertex_t* v2, const pvr_vertex_t *v3,
|
||||
pvr_vertex_t* v1out, pvr_vertex_t* v2out, pvr_vertex_t* v3out, pvr_vertex_t* v4out
|
||||
) {
|
||||
|
||||
/* Fast out. Let's just see if everything is in front of the clip plane (and as in OpenGL Z comes out of the screen
|
||||
* we check to see if they are all < -dist
|
||||
*/
|
||||
|
||||
typedef unsigned char uint8;
|
||||
uint8 visible = ((uint8) v1->z < plane_dist) | ((uint8) v2->z < plane_dist) << 1 | ((uint8) v3->z < plane_dist) << 2;
|
||||
|
||||
switch(visible) {
|
||||
case 0b000:
|
||||
/* If behind is zero, then none of the vertices are visible */
|
||||
return TRIANGLE_CLIP_RESULT_DROP_TRIANGLE;
|
||||
case 0b111:
|
||||
/* If behind is zero, then none of the vertices are visible */
|
||||
return TRIANGLE_CLIP_RESULT_NO_CHANGE;
|
||||
case 0b101:
|
||||
case 0b110:
|
||||
case 0b011: {
|
||||
/* Two vertices are visible */
|
||||
/* Tricky case. If two vertices are visible then manipulating the other one is going to change the shape of the
|
||||
* triangle. So we have to clip both lines, and output a new vertex.
|
||||
*/
|
||||
|
||||
return TRIANGLE_CLIP_RESULT_ALTERED_AND_CREATED_VERTEX;
|
||||
} break;
|
||||
default: {
|
||||
/* One vertex is visible */
|
||||
/* This is the "easy" case, we simply find the vertex which is visible, and clip the lines to the other 2 against the plane */
|
||||
|
||||
pvr_vertex_t tmp1, tmp2;
|
||||
float t1, t2;
|
||||
|
||||
if(visible == 0b001) {
|
||||
ClipResult l1 = clipLineToNearZ(&v1->x, &v2->x, plane_dist, &tmp1, &t1);
|
||||
ClipResult l2 = clipLineToNearZ(&v1->x, &v3->x, plane_dist, &tmp2, &t2);
|
||||
|
||||
*v1out = *v1;
|
||||
*v2out = tmp1;
|
||||
*v3out = tmp2;
|
||||
} else if(visible == 0b010) {
|
||||
ClipResult l1 = clipLineToNearZ(&v2->x, &v1->x, plane_dist, &tmp1, &t1);
|
||||
ClipResult l2 = clipLineToNearZ(&v2->x, &v3->x, plane_dist, &tmp2, &t2);
|
||||
|
||||
*v1out = tmp1;
|
||||
*v2out = *v2;
|
||||
*v3out = tmp2;
|
||||
} else {
|
||||
ClipResult l1 = clipLineToNearZ(&v3->x, &v1->x, plane_dist, &tmp1, &t1);
|
||||
ClipResult l2 = clipLineToNearZ(&v3->x, &v2->x, plane_dist, &tmp2, &t2);
|
||||
|
||||
*v1out = tmp1;
|
||||
*v2out = tmp2;
|
||||
*v3out = *v3;
|
||||
}
|
||||
|
||||
return TRIANGLE_CLIP_RESULT_ALTERED_VERTICES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
45
GL/clip.h
45
GL/clip.h
|
@ -5,6 +5,22 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* If we're not on the Dreamcast then define pvr_vertex_t
|
||||
* (this if for testing only)
|
||||
*/
|
||||
#ifndef _arch_dreamcast
|
||||
typedef struct {
|
||||
uint32 flags; /**< \brief TA command (vertex flags) */
|
||||
float x; /**< \brief X coordinate */
|
||||
float y; /**< \brief Y coordinate */
|
||||
float z; /**< \brief Z coordinate */
|
||||
float u; /**< \brief Texture U coordinate */
|
||||
float v; /**< \brief Texture V coordinate */
|
||||
uint32 argb; /**< \brief Vertex color */
|
||||
uint32 oargb; /**< \brief Vertex offset color */
|
||||
} pvr_vertex_t;
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
CLIP_RESULT_ALL_IN_FRONT,
|
||||
CLIP_RESULT_ALL_BEHIND,
|
||||
|
@ -15,6 +31,35 @@ typedef enum {
|
|||
|
||||
ClipResult clipLineToNearZ(const float* v1, const float* v2, const float dist, float* vout, float* t);
|
||||
|
||||
|
||||
/* There are 4 possible situations we'll hit when clipping triangles:
|
||||
*
|
||||
* 1. The entire triangle was in front of the near plane, so we do nothing
|
||||
* 2. The entire triangle was behind the near plane, so we drop it completely
|
||||
* 3. One vertex was behind the clip plane. In this case we need to create a new vertex and an additional triangle
|
||||
* 4. Two vertices were behind the clip plane, we can simply move them so the triangle no longer intersects
|
||||
*/
|
||||
typedef enum {
|
||||
TRIANGLE_CLIP_RESULT_NO_CHANGE,
|
||||
TRIANGLE_CLIP_RESULT_DROP_TRIANGLE,
|
||||
TRIANGLE_CLIP_RESULT_ALTERED_AND_CREATED_VERTEX,
|
||||
TRIANGLE_CLIP_RESULT_ALTERED_VERTICES
|
||||
} TriangleClipResult;
|
||||
|
||||
/* Clips a triangle from a triangle strip to a near-z plane. Alternating triangles in a strip switch vertex ordering
|
||||
* so the number of the triangle must be passed in (vn - 2).
|
||||
*
|
||||
* Note that clipping a triangle with a plane may create a quadrilateral, so this function must have
|
||||
* a space to output the 4th vertex.
|
||||
*
|
||||
* The outputs can be the same as the inputs.
|
||||
*/
|
||||
TriangleClipResult clipTriangleToNearZ(
|
||||
const float plane_dist,
|
||||
const unsigned short triangle_n, const pvr_vertex_t* v1, const pvr_vertex_t* v2, const pvr_vertex_t *v3,
|
||||
pvr_vertex_t* v1out, pvr_vertex_t* v2out, pvr_vertex_t* v3out, pvr_vertex_t* v4out
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
87
GL/draw.c
87
GL/draw.c
|
@ -190,12 +190,23 @@ inline void transformNormalToEyeSpace(GLfloat* normal) {
|
|||
mat_trans_normal3(normal[0], normal[1], normal[2]);
|
||||
}
|
||||
|
||||
/* If this has a value other than zero, it must be negative! */
|
||||
#define NEAR_DEPTH 0.0f
|
||||
|
||||
static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum type, const GLvoid* indices) {
|
||||
static GLfloat normal[3] = {0.0f, 0.0f, -1.0f};
|
||||
static GLfloat eye_P[3];
|
||||
static GLfloat eye_N[3];
|
||||
|
||||
/* When clipping triangle strips we need to keep a stash of the last two vertices *before*
|
||||
* they were manipulated, because, imagine this scenario:
|
||||
* - A triangle has 2 vertices hidden
|
||||
* - We manipulate those 2 vertices to coincide with the near plane
|
||||
* - We end that triangle strip, then start a new one with the next triangle
|
||||
* - That triangle needs to be formed with the original vertices
|
||||
*/
|
||||
static pvr_vertex_t clip_stash[2];
|
||||
|
||||
if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) {
|
||||
return;
|
||||
}
|
||||
|
@ -235,8 +246,10 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
|
|||
|
||||
GLboolean lighting_enabled = isLightingEnabled();
|
||||
|
||||
GLushort i, last_vertex;
|
||||
for(i = first; i < count; ++i) {
|
||||
GLushort i, last_vertex
|
||||
GLshort rel; // Has to be signed as we drop below zero so we can re-enter the loop at 1.
|
||||
|
||||
for(rel = 0, i = first; i < count; ++i, ++rel) {
|
||||
pvr_vertex_t* vertex = (pvr_vertex_t*) dst;
|
||||
vertex->u = vertex->v = 0.0f;
|
||||
vertex->argb = 0;
|
||||
|
@ -308,6 +321,8 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
|
|||
}
|
||||
|
||||
_applyRenderMatrix(); /* Apply the Render Matrix Stack */
|
||||
|
||||
// FIXME: Don't perspective divide!
|
||||
transformVertex(&vertex->x, &vertex->x, &vertex->y, &vertex->z);
|
||||
|
||||
/* The PVR doesn't support quads, only triangle strips, so we need to
|
||||
|
@ -325,6 +340,74 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
|
|||
*(vertex - 1) = tmp;
|
||||
}
|
||||
|
||||
// Store this for the clip stash
|
||||
pvr_vertex_t original_vertex = *dst;
|
||||
|
||||
if(rel >= 2) {
|
||||
/* We have at least one complete triangle, let's start clipping! */
|
||||
pvr_vertex_t* v1 = &clip_stash[0];
|
||||
pvr_vertex_t* v2 = &clip_stash[1];
|
||||
pvr_vertex_t* v3 = dst;
|
||||
|
||||
pvr_vertex_t* v1out = dst - 2;
|
||||
pvr_vertex_t* v2out = dst - 1;
|
||||
pvr_vertex_t* v3out = v3;
|
||||
pvr_vertex_t v4out;
|
||||
|
||||
TriangleClipResult ret = clipTriangleToNearZ(
|
||||
NEAR_DEPTH,
|
||||
rel - 2,
|
||||
v1, v2, v3,
|
||||
v1out, v2out, v3out, &v4out
|
||||
);
|
||||
|
||||
if(ret == TRIANGLE_CLIP_RESULT_DROP_TRIANGLE) {
|
||||
/* If we're here, then none of the 3 points were visible, that means we drop the entire triangle and start
|
||||
* anew with the next one. We rollback rel as we always need 3 vertices and if this was the first triangle in the strip
|
||||
* we need to build up the stash again
|
||||
* we point dst back at the first vertex. We would actually have access space at the end of the array
|
||||
* so we move that back too (this won't reallocate, we never reallocate on shrink unless we call vector_shrink_to_fit
|
||||
*/
|
||||
dst = dst - 3; // This might seem like we're going back too many, but we increment further down
|
||||
rel = rel - 3; // This might drop down to -1, but the next loop will go up to 0 again
|
||||
|
||||
aligned_vector_resize(
|
||||
&activePolyList()->vector,
|
||||
activePolyList->size - 3
|
||||
);
|
||||
|
||||
} else if(ret == TRIANGLE_CLIP_RESULT_ALTERED_VERTICES) {
|
||||
/*
|
||||
* Two vertices were behind the clip plane, we just manipulated them.
|
||||
we have to end the triangle strip here and pick up next vertex */
|
||||
|
||||
v3out->flags = PVR_CMD_VERTEX_EOL;
|
||||
|
||||
/* Now we push back the original 2 vertices, so that the next triangle strip will be properly
|
||||
* formed (or dropped) next time around */
|
||||
aligned_vector_resize(
|
||||
&activePolyList()->vector,
|
||||
activePolyList->size + 2
|
||||
);
|
||||
|
||||
*(++dst) = clip_stash[1];
|
||||
*(++dst) = original_vertex;
|
||||
|
||||
} else if(ret == TRIANGLE_CLIP_RESULT_ALTERED_AND_CREATED_VERTEX) {
|
||||
/* One vertex was behind the clip plane, we need to create another triangle */
|
||||
/* We need to push back v4 and then deal with a possible reallocation by updating dst */
|
||||
|
||||
} else {
|
||||
/* OK nothing changed, don't do anything */
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the clip stash */
|
||||
clip_stash[0] = clip_stash[1];
|
||||
clip_stash[1] = original_vertex;
|
||||
|
||||
//FIXME: Peform perspective division
|
||||
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
#include "../include/gl.h"
|
||||
#include "../containers/aligned_vector.h"
|
||||
#include "../containers/named_array.h"
|
||||
|
||||
#include "./clip.h"
|
||||
#include "./pvr.h"
|
||||
|
||||
#define TRACE_ENABLED 0
|
||||
#define TRACE() if(TRACE_ENABLED) {fprintf(stderr, "%s\n", __func__);}
|
||||
|
|
Loading…
Reference in New Issue
Block a user