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;
|
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" {
|
extern "C" {
|
||||||
#endif
|
#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 {
|
typedef enum {
|
||||||
CLIP_RESULT_ALL_IN_FRONT,
|
CLIP_RESULT_ALL_IN_FRONT,
|
||||||
CLIP_RESULT_ALL_BEHIND,
|
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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#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]);
|
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 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 normal[3] = {0.0f, 0.0f, -1.0f};
|
||||||
static GLfloat eye_P[3];
|
static GLfloat eye_P[3];
|
||||||
static GLfloat eye_N[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)) {
|
if(!(ENABLED_VERTEX_ATTRIBUTES & VERTEX_ENABLED_FLAG)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -235,8 +246,10 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
|
||||||
|
|
||||||
GLboolean lighting_enabled = isLightingEnabled();
|
GLboolean lighting_enabled = isLightingEnabled();
|
||||||
|
|
||||||
GLushort i, last_vertex;
|
GLushort i, last_vertex
|
||||||
for(i = first; i < count; ++i) {
|
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;
|
pvr_vertex_t* vertex = (pvr_vertex_t*) dst;
|
||||||
vertex->u = vertex->v = 0.0f;
|
vertex->u = vertex->v = 0.0f;
|
||||||
vertex->argb = 0;
|
vertex->argb = 0;
|
||||||
|
@ -308,6 +321,8 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyRenderMatrix(); /* Apply the Render Matrix Stack */
|
_applyRenderMatrix(); /* Apply the Render Matrix Stack */
|
||||||
|
|
||||||
|
// FIXME: Don't perspective divide!
|
||||||
transformVertex(&vertex->x, &vertex->x, &vertex->y, &vertex->z);
|
transformVertex(&vertex->x, &vertex->x, &vertex->y, &vertex->z);
|
||||||
|
|
||||||
/* The PVR doesn't support quads, only triangle strips, so we need to
|
/* 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;
|
*(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;
|
++dst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,9 @@
|
||||||
#include "../include/gl.h"
|
#include "../include/gl.h"
|
||||||
#include "../containers/aligned_vector.h"
|
#include "../containers/aligned_vector.h"
|
||||||
#include "../containers/named_array.h"
|
#include "../containers/named_array.h"
|
||||||
|
|
||||||
#include "./clip.h"
|
#include "./clip.h"
|
||||||
|
#include "./pvr.h"
|
||||||
|
|
||||||
#define TRACE_ENABLED 0
|
#define TRACE_ENABLED 0
|
||||||
#define TRACE() if(TRACE_ENABLED) {fprintf(stderr, "%s\n", __func__);}
|
#define TRACE() if(TRACE_ENABLED) {fprintf(stderr, "%s\n", __func__);}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user