Make the first clip test pass
This commit is contained in:
parent
34741420bc
commit
5b9a0502b5
136
GL/flush.c
136
GL/flush.c
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "flush.h"
|
#include "flush.h"
|
||||||
|
|
||||||
|
#define CLIP_DEBUG 1
|
||||||
|
|
||||||
#define TA_SQ_ADDR (unsigned int *)(void *) \
|
#define TA_SQ_ADDR (unsigned int *)(void *) \
|
||||||
(0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0))
|
(0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0))
|
||||||
|
|
||||||
|
@ -20,10 +22,85 @@ static PolyList TR_LIST;
|
||||||
|
|
||||||
static const int STRIDE = sizeof(Vertex) / sizeof(GLuint);
|
static const int STRIDE = sizeof(Vertex) / sizeof(GLuint);
|
||||||
|
|
||||||
|
#define CLIP_TO_PLANE(vert1, vert2) \
|
||||||
|
do { \
|
||||||
|
float t = _glClipLineToNearZ((vert1), (vert2), out); \
|
||||||
|
interpolateVec2((vert1)->uv, (vert2)->uv, t, out->uv); \
|
||||||
|
interpolateVec3((vert1)->nxyz, (vert2)->nxyz, t, out->nxyz); \
|
||||||
|
interpolateVec2((vert1)->st, (vert2)->st, t, out->st); \
|
||||||
|
interpolateColour((vert1)->bgra, (vert2)->bgra, t, out->bgra); \
|
||||||
|
} while(0); \
|
||||||
|
|
||||||
|
|
||||||
|
GL_FORCE_INLINE float _glClipLineToNearZ(const Vertex* v1, const Vertex* v2, Vertex* vout) {
|
||||||
|
const float d0 = v1->w;
|
||||||
|
const float d1 = v2->w;
|
||||||
|
|
||||||
|
assert(isVisible(v1) ^ isVisible(v2));
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* FIXME: Disabled until determined necessary */
|
||||||
|
|
||||||
|
/* We need to shift 't' a little, to avoid the possibility that a
|
||||||
|
* rounding error leaves the new vertex behind the near plane. We shift
|
||||||
|
* according to the direction we're clipping across the plane */
|
||||||
|
const float epsilon = (d0 < d1) ? 0.000001 : -0.000001;
|
||||||
|
#else
|
||||||
|
const float epsilon = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
float t = MATH_Fast_Divide(d0, (d0 - d1))+ epsilon;
|
||||||
|
|
||||||
|
vout->xyz[0] = MATH_fmac(v2->xyz[0] - v1->xyz[0], t, v1->xyz[0]);
|
||||||
|
vout->xyz[1] = MATH_fmac(v2->xyz[1] - v1->xyz[1], t, v1->xyz[1]);
|
||||||
|
vout->xyz[2] = MATH_fmac(v2->xyz[2] - v1->xyz[2], t, v1->xyz[2]);
|
||||||
|
vout->w = MATH_fmac(v2->w - v1->w, t, v1->w);
|
||||||
|
|
||||||
|
#if CLIP_DEBUG
|
||||||
|
printf(
|
||||||
|
"(%f, %f, %f, %f) -> %f -> (%f, %f, %f, %f) = (%f, %f, %f, %f)\n",
|
||||||
|
v1->xyz[0], v1->xyz[1], v1->xyz[2], v1->w, t,
|
||||||
|
v2->xyz[0], v2->xyz[1], v2->xyz[2], v2->w,
|
||||||
|
vout->xyz[0], vout->xyz[1], vout->xyz[2], vout->w
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_FORCE_INLINE void interpolateFloat(const float v1, const float v2, const float t, float* out) {
|
||||||
|
*out = MATH_fmac(v2 - v1,t, v1);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_FORCE_INLINE void interpolateVec2(const float* v1, const float* v2, const float t, float* out) {
|
||||||
|
interpolateFloat(v1[0], v2[0], t, &out[0]);
|
||||||
|
interpolateFloat(v1[1], v2[1], t, &out[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_FORCE_INLINE void interpolateVec3(const float* v1, const float* v2, const float t, float* out) {
|
||||||
|
interpolateFloat(v1[0], v2[0], t, &out[0]);
|
||||||
|
interpolateFloat(v1[1], v2[1], t, &out[1]);
|
||||||
|
interpolateFloat(v1[2], v2[2], t, &out[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_FORCE_INLINE void interpolateVec4(const float* v1, const float* v2, const float t, float* out) {
|
||||||
|
interpolateFloat(v1[0], v2[0], t, &out[0]);
|
||||||
|
interpolateFloat(v1[1], v2[1], t, &out[1]);
|
||||||
|
interpolateFloat(v1[2], v2[2], t, &out[2]);
|
||||||
|
interpolateFloat(v1[3], v2[3], t, &out[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
GL_FORCE_INLINE void interpolateColour(const uint8_t* v1, const uint8_t* v2, const float t, uint8_t* out) {
|
||||||
|
out[0] = v1[0] + (uint32_t) (((float) (v2[0] - v1[0])) * t);
|
||||||
|
out[1] = v1[1] + (uint32_t) (((float) (v2[1] - v1[1])) * t);
|
||||||
|
out[2] = v1[2] + (uint32_t) (((float) (v2[2] - v1[2])) * t);
|
||||||
|
out[3] = v1[3] + (uint32_t) (((float) (v2[3] - v1[3])) * t);
|
||||||
|
}
|
||||||
|
|
||||||
static Vertex* interpolate_vertex(const Vertex* v0, const Vertex* v1, Vertex* out) {
|
static Vertex* interpolate_vertex(const Vertex* v0, const Vertex* v1, Vertex* out) {
|
||||||
/* If v0 is in front of the near plane, and v1 is behind the near plane, this
|
/* If v0 is in front of the near plane, and v1 is behind the near plane, this
|
||||||
* generates a vertex *on* the near plane */
|
* generates a vertex *on* the near plane */
|
||||||
|
CLIP_TO_PLANE(v0, v1);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +108,7 @@ GL_FORCE_INLINE ListIterator* header_reset(ListIterator* it, Vertex* header) {
|
||||||
it->it = header;
|
it->it = header;
|
||||||
it->visibility = 0;
|
it->visibility = 0;
|
||||||
it->triangle_count = 0;
|
it->triangle_count = 0;
|
||||||
|
it->stack_idx = -1;
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,11 +118,19 @@ GL_FORCE_INLINE Vertex* current_postinc(ListIterator* it) {
|
||||||
}
|
}
|
||||||
|
|
||||||
it->remaining--;
|
it->remaining--;
|
||||||
return it->current++;
|
Vertex* current = it->current;
|
||||||
|
it->current++;
|
||||||
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
GL_FORCE_INLINE Vertex* push_stack(ListIterator* it) {
|
GL_FORCE_INLINE Vertex* push_stack(ListIterator* it) {
|
||||||
return &it->stack[it->stack_idx++];
|
#if CLIP_DEBUG
|
||||||
|
printf("Using stack: %d\n", it->stack_idx + 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(it->stack_idx + 1 < MAX_STACK);
|
||||||
|
|
||||||
|
return &it->stack[++it->stack_idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
GL_FORCE_INLINE GLboolean shift(ListIterator* it, Vertex* new_vertex) {
|
GL_FORCE_INLINE GLboolean shift(ListIterator* it, Vertex* new_vertex) {
|
||||||
|
@ -67,6 +153,21 @@ GL_FORCE_INLINE GLboolean shift(ListIterator* it, Vertex* new_vertex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ListIterator* _glIteratorNext(ListIterator* it) {
|
ListIterator* _glIteratorNext(ListIterator* it) {
|
||||||
|
/* None remaining in the list, and the stack is empty */
|
||||||
|
if(!it->remaining && it->stack_idx == -1) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return any vertices we generated */
|
||||||
|
if(it->stack_idx > -1) {
|
||||||
|
#if CLIP_DEBUG
|
||||||
|
printf("Yielding stack: %d\n", it->stack_idx);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
it->it = &it->stack[it->stack_idx--];
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
if(!isVertex(it->current)) {
|
if(!isVertex(it->current)) {
|
||||||
return header_reset(it, current_postinc(it));
|
return header_reset(it, current_postinc(it));
|
||||||
} else {
|
} else {
|
||||||
|
@ -80,6 +181,7 @@ ListIterator* _glIteratorNext(ListIterator* it) {
|
||||||
/* We reached the end so just
|
/* We reached the end so just
|
||||||
* return the oldest until they're gone */
|
* return the oldest until they're gone */
|
||||||
it->it = it->triangle[0];
|
it->it = it->triangle[0];
|
||||||
|
printf("Bailing early!\n");
|
||||||
return (it->it) ? it : NULL;
|
return (it->it) ? it : NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,18 +194,34 @@ ListIterator* _glIteratorNext(ListIterator* it) {
|
||||||
it->it = it->triangle[0];
|
it->it = it->triangle[0];
|
||||||
return it;
|
return it;
|
||||||
break;
|
break;
|
||||||
case B100:
|
case B100: {
|
||||||
/* First visible only */
|
/* First visible only */
|
||||||
it->triangle[1] = interpolate_vertex(it->triangle[0], it->triangle[1], push_stack(it));
|
Vertex* gen2 = push_stack(it);
|
||||||
it->triangle[2] = interpolate_vertex(it->triangle[0], it->triangle[2], push_stack(it));
|
Vertex* gen1 = push_stack(it);
|
||||||
|
|
||||||
|
/* Make sure we transfer the flags.. we don't
|
||||||
|
* want to disrupt the strip */
|
||||||
|
gen1->flags = it->triangle[1]->flags;
|
||||||
|
gen2->flags = it->triangle[2]->flags;
|
||||||
|
|
||||||
|
interpolate_vertex(it->triangle[0], it->triangle[1], gen1);
|
||||||
|
interpolate_vertex(it->triangle[0], it->triangle[2], gen2);
|
||||||
it->visibility = B111; /* All visible now, yay! */
|
it->visibility = B111; /* All visible now, yay! */
|
||||||
|
|
||||||
assert(isVisible(it->triangle[1]));
|
assert(isVisible(gen1));
|
||||||
assert(isVisible(it->triangle[2]));
|
assert(isVisible(gen2));
|
||||||
|
assert(isVertex(gen1));
|
||||||
|
assert(isVertex(gen2));
|
||||||
|
|
||||||
it->it = it->triangle[0];
|
it->it = it->triangle[0];
|
||||||
|
|
||||||
|
/* We're returning v0, and we've pushed
|
||||||
|
* v1 and v2 to the stack, so next time
|
||||||
|
* around we'll need to consume and shift
|
||||||
|
* the next vertex from the source list */
|
||||||
|
it->triangle_count--;
|
||||||
return it;
|
return it;
|
||||||
break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
GL/flush.h
12
GL/flush.h
|
@ -28,22 +28,25 @@ typedef struct {
|
||||||
Vertex* it;
|
Vertex* it;
|
||||||
|
|
||||||
/* < 8. Bitmask of the last 3 vertices */
|
/* < 8. Bitmask of the last 3 vertices */
|
||||||
uint8_t visibility;
|
|
||||||
uint8_t triangle_count;
|
|
||||||
Vertex* triangle[3];
|
Vertex* triangle[3];
|
||||||
|
|
||||||
/* Stack of temporary vertices */
|
/* Stack of temporary vertices */
|
||||||
Vertex stack[MAX_STACK];
|
Vertex stack[MAX_STACK];
|
||||||
int8_t stack_idx;
|
int8_t stack_idx;
|
||||||
|
uint8_t visibility;
|
||||||
|
uint8_t triangle_count;
|
||||||
|
uint8_t padding;
|
||||||
} ListIterator;
|
} ListIterator;
|
||||||
|
|
||||||
inline ListIterator* _glIteratorBegin(void* src, int n) {
|
inline ListIterator* _glIteratorBegin(void* src, int n) {
|
||||||
ListIterator* it = (ListIterator*) malloc(sizeof(ListIterator));
|
ListIterator* it = (ListIterator*) malloc(sizeof(ListIterator));
|
||||||
it->remaining = n;
|
it->remaining = n - 1;
|
||||||
it->current = (Vertex*) src;
|
it->it = (Vertex*) src;
|
||||||
|
it->current = it->it + 1;
|
||||||
it->stack_idx = -1;
|
it->stack_idx = -1;
|
||||||
it->triangle_count = 0;
|
it->triangle_count = 0;
|
||||||
it->visibility = 0;
|
it->visibility = 0;
|
||||||
|
it->triangle[0] = it->triangle[1] = it->triangle[2] = NULL;
|
||||||
return (n) ? it : NULL;
|
return (n) ? it : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +59,7 @@ GL_FORCE_INLINE GLboolean isVertex(const Vertex* vertex) {
|
||||||
|
|
||||||
GL_FORCE_INLINE GLboolean isVisible(const Vertex* vertex) {
|
GL_FORCE_INLINE GLboolean isVisible(const Vertex* vertex) {
|
||||||
if(!vertex) return GL_FALSE;
|
if(!vertex) return GL_FALSE;
|
||||||
|
printf("Z: %f, W: %f\n", vertex->xyz[2], vertex->w);
|
||||||
return vertex->w >= 0 && vertex->xyz[2] >= -vertex->w;
|
return vertex->w >= 0 && vertex->xyz[2] >= -vertex->w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,6 @@ typedef enum {
|
||||||
#define G8IDX 1
|
#define G8IDX 1
|
||||||
#define B8IDX 0
|
#define B8IDX 0
|
||||||
|
|
||||||
float _glClipLineToNearZ(const Vertex* v1, const Vertex* v2, Vertex* vout);
|
|
||||||
void _glClipTriangleStrip(SubmissionTarget* target, uint8_t fladeShade);
|
void _glClipTriangleStrip(SubmissionTarget* target, uint8_t fladeShade);
|
||||||
|
|
||||||
PolyList *_glActivePolyList();
|
PolyList *_glActivePolyList();
|
||||||
|
|
|
@ -2,32 +2,52 @@
|
||||||
|
|
||||||
#include "../utils/test.h"
|
#include "../utils/test.h"
|
||||||
#include "../GL/flush.h"
|
#include "../GL/flush.h"
|
||||||
|
#include "../containers/aligned_vector.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
struct VertexBuilder {
|
struct VertexBuilder {
|
||||||
|
VertexBuilder() {
|
||||||
|
aligned_vector_init(&list_, sizeof(Vertex));
|
||||||
|
}
|
||||||
|
|
||||||
|
~VertexBuilder() {
|
||||||
|
aligned_vector_clear(&list_);
|
||||||
|
}
|
||||||
|
|
||||||
VertexBuilder& add_header() {
|
VertexBuilder& add_header() {
|
||||||
Vertex v;
|
Vertex v;
|
||||||
v.flags = 100; // I dunno what this bit of memory would be
|
v.flags = 100; // I dunno what this bit of memory would be
|
||||||
list_.push_back(std::move(v));
|
|
||||||
|
aligned_vector_push_back(&list_, &v, 1);
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexBuilder& add(float x, float y, float z, float w) {
|
VertexBuilder& add(float x, float y, float z, float w) {
|
||||||
Vertex v;
|
Vertex v;
|
||||||
|
v.flags = PVR_CMD_VERTEX;
|
||||||
v.xyz[0] = x;
|
v.xyz[0] = x;
|
||||||
v.xyz[1] = y;
|
v.xyz[1] = y;
|
||||||
v.xyz[2] = z;
|
v.xyz[2] = z;
|
||||||
v.w = w;
|
v.w = w;
|
||||||
|
aligned_vector_push_back(&list_, &v, 1);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Vertex> done() {
|
VertexBuilder& add_last(float x, float y, float z, float w) {
|
||||||
return list_;
|
add(x, y, z, w);
|
||||||
|
Vertex* back = (Vertex*) aligned_vector_back(&list_);
|
||||||
|
back->flags = PVR_CMD_VERTEX_EOL;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<Vertex*, int> done() {
|
||||||
|
return std::make_pair((Vertex*) aligned_vector_at(&list_, 0), list_.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Vertex> list_;
|
AlignedVector list_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NearZClippingTests : public gldc::test::GLdcTestCase {
|
class NearZClippingTests : public gldc::test::GLdcTestCase {
|
||||||
|
@ -39,31 +59,34 @@ public:
|
||||||
|
|
||||||
VertexBuilder builder;
|
VertexBuilder builder;
|
||||||
|
|
||||||
std::vector<Vertex> list = builder.
|
auto list = builder.
|
||||||
add_header().
|
add_header().
|
||||||
add(1, 1, 2, 1).
|
add(1, 1, 2, 1).
|
||||||
add(1, 0, 2, -1).
|
add(1, 0, 2, -1).
|
||||||
add(0, 1, 2, -1).done();
|
add_last(0, 1, 2, -1).done();
|
||||||
|
|
||||||
ListIterator* it = _glIteratorBegin(&list[0], list.size());
|
ListIterator* it = _glIteratorBegin(list.first, list.second);
|
||||||
Vertex* v0 = it->current;
|
Vertex* v0 = it->it;
|
||||||
assert_is_not_null(v0);
|
assert_is_not_null(v0);
|
||||||
assert_false(isVertex(v0)); // Should be a header
|
assert_false(isVertex(v0)); // Should be a header
|
||||||
|
|
||||||
it = _glIteratorNext(it);
|
it = _glIteratorNext(it);
|
||||||
assert_is_not_null(it);
|
assert_is_not_null(it);
|
||||||
Vertex* v1 = it->current;
|
Vertex* v1 = it->it;
|
||||||
assert_is_not_null(v1);
|
assert_is_not_null(v1);
|
||||||
|
assert_true(isVertex(v1));
|
||||||
|
|
||||||
it = _glIteratorNext(it);
|
it = _glIteratorNext(it);
|
||||||
assert_is_not_null(it);
|
assert_is_not_null(it);
|
||||||
Vertex* v2 = it->current;
|
Vertex* v2 = it->it;
|
||||||
assert_is_not_null(v2);
|
assert_is_not_null(v2);
|
||||||
|
assert_true(isVertex(v2));
|
||||||
|
|
||||||
it = _glIteratorNext(it);
|
it = _glIteratorNext(it);
|
||||||
assert_is_not_null(it);
|
assert_is_not_null(it);
|
||||||
Vertex* v3 = it->current;
|
Vertex* v3 = it->it;
|
||||||
assert_is_not_null(v3);
|
assert_is_not_null(v3);
|
||||||
|
assert_true(isVertex(v3));
|
||||||
|
|
||||||
it = _glIteratorNext(it);
|
it = _glIteratorNext(it);
|
||||||
assert_is_null(it);
|
assert_is_null(it);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user