Fix a bunch of issues with clipping (almost working)

This commit is contained in:
Luke Benstead 2023-04-21 20:38:21 +01:00
parent 72c375f87c
commit baa275b41b
2 changed files with 236 additions and 184 deletions

View File

@ -13,9 +13,6 @@
(0xe0000000 | (((uint32_t)0x10000000) & 0x03ffffe0))
static volatile uint32_t* PVR_LMMODE0 = (uint32_t*) 0xA05F6884;
GL_FORCE_INLINE bool glIsVertex(const float flags) {
return flags == GPU_CMD_VERTEX_EOL || flags == GPU_CMD_VERTEX;
}
@ -78,7 +75,7 @@ GL_FORCE_INLINE void _glSubmitHeaderOrVertex(volatile uint32_t* d, const Vertex*
#endif
#if CLIP_DEBUG
printf("Submitting: %x (%x)\n", v, v->flags);
fprintf(stderr, "Submitting: %x (%x)\n", v, v->flags);
#endif
uint32_t *s = (uint32_t*) v;
@ -128,8 +125,9 @@ static inline void _glClipEdge(const Vertex* v1, const Vertex* v2, Vertex* vout)
}
#define SPAN_SORT_CFG 0x005F8030
static volatile int *pvrdmacfg = (int*)0xA05F6888;
static volatile int *qacr = (int*)0xFF000038;
static volatile uint32_t* PVR_LMMODE0 = (uint32_t*) 0xA05F6884;
static volatile uint32_t *PVR_LMMODE1 = (uint32_t*) 0xA05F6888;
static volatile uint32_t *QACR = (uint32_t*) 0xFF000038;
void SceneListSubmit(void* src, int n) {
/* You need at least a header, and 3 vertices to render anything */
@ -142,11 +140,11 @@ void SceneListSubmit(void* src, int n) {
PVR_SET(SPAN_SORT_CFG, 0x0);
//Set PVR DMA registers
pvrdmacfg[0] = 1;
pvrdmacfg[1] = 0;
*PVR_LMMODE0 = 0;
*PVR_LMMODE1 = 0;
//Set QACR registers
qacr[1] = qacr[0] = 0x11;
QACR[1] = QACR[0] = 0x11;
volatile uint32_t *d = SQ_BASE_ADDRESS;
@ -156,31 +154,24 @@ void SceneListSubmit(void* src, int n) {
/* The most vertices ever in the queue is 5 (as some clipping operations
* produce and additional couple of vertice, but we add one more so the ring buffer doesn't
* trip over itself (e.g. if tail == head we can guarantee it's empty, not full) */
Vertex __attribute__((aligned(32))) queue[6];
Vertex __attribute__((aligned(32))) queue[4];
const int queue_capacity = sizeof(queue) / sizeof(Vertex);
Vertex* vertex = (Vertex*) src;
uint32_t visible_mask = 0;
uint32_t counter = 0;
#define QUEUE_OFFSET(n) (queue + ((queue_head + (n)) % queue_capacity))
#define PUSH_VERTEX(v) \
do { \
memcpy_vertex(queue + queue_tail, (v)); \
visible_mask = (visible_mask << 1) | ((v)->xyz[2] >= -(v)->w); \
visible_mask = (visible_mask >> 1) | ((v)->xyz[2] >= -(v)->w) << 2; \
assert(visible_mask < 15); \
queue_tail = (queue_tail + 1) % queue_capacity; \
counter++; \
} while(0)
/* Assume first entry is a header */
_glSubmitHeaderOrVertex(d, vertex++);
/* Push first 2 vertices of the strip */
PUSH_VERTEX(vertex);
++vertex;
PUSH_VERTEX(vertex);
++vertex;
n -= 3;
while(n--) {
Vertex* current = vertex;
if(!glIsVertex(vertex->flags)) {
@ -192,18 +183,38 @@ void SceneListSubmit(void* src, int n) {
++vertex;
}
if(counter < 3) {
continue;
}
switch(visible_mask) {
case 0:
queue_head = (queue_head + 1) % queue_capacity;
--counter;
continue;
break;
case 7:
/* All visible, push the first vertex and move on */
_glPerspectiveDivideVertex(&queue[queue_head], h);
_glSubmitHeaderOrVertex(d, &queue[queue_head]);
if(glIsLastVertex(current->flags)) {
/* If this was the last vertex in the strip, we need to flush the queue and then
restart it again */
queue_head = (queue_head + 1) % queue_capacity;
counter--;
while(counter--) {
// There are 3 vertices, so we push the first one
_glPerspectiveDivideVertex(&queue[queue_head], h);
_glSubmitHeaderOrVertex(d, &queue[queue_head]);
queue_head = (queue_head + 1) % queue_capacity;
}
visible_mask = 0;
continue;
}
break;
case 4:
case 1:
/* First vertex was visible */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
@ -221,11 +232,14 @@ void SceneListSubmit(void* src, int n) {
cross back*/
b.flags = v2->flags;
// v0 is already at the head of the queue
memcpy_vertex(QUEUE_OFFSET(1), &a); // replace
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
PUSH_VERTEX(&b); /* Additional vertex */
visible_mask = 15; /* All 4 vertices visible */
_glPerspectiveDivideVertex(v0, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, v0);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &b);
}
break;
case 2:
@ -234,88 +248,104 @@ void SceneListSubmit(void* src, int n) {
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex* v2 = &queue[(queue_head + 2) % queue_capacity];
const Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
const Vertex* v2 = &queue[(queue_head + 2) % queue_capacity];
_glClipEdge(v0, v1, &a);
_glClipEdge(v1, v2, &b);
a.flags = GPU_CMD_VERTEX;
b.flags = GPU_CMD_VERTEX_EOL;
memcpy_vertex(QUEUE_OFFSET(0), &a); // replace
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
visible_mask = 7; /* All 3 vertices visible */
_glPerspectiveDivideVertex(v0, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, v0);
_glSubmitHeaderOrVertex(d, &b);
}
break;
case 6: /* First and second vertex were visible */
case 3: /* First and second vertex were visible */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex __attribute__((aligned(32))) v1 = queue[(queue_head + 1) % queue_capacity];
Vertex* v2 = &queue[(queue_head + 2) % queue_capacity];
_glClipEdge(v1, v2, &a);
_glClipEdge(&v1, v2, &a);
_glClipEdge(v2, v0, &b);
a.flags = v2->flags;
b.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
PUSH_VERTEX(v1); /* Additional vertex */
PUSH_VERTEX(&a); /* Additional vertex */
visible_mask = 31; /* All 5 vertices visible */
_glPerspectiveDivideVertex(v0, h);
_glPerspectiveDivideVertex(&v1, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, v0);
_glSubmitHeaderOrVertex(d, &v1);
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &v1);
_glSubmitHeaderOrVertex(d, &a);
}
break;
case 1:
case 4:
/* Third vertex was visible. */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex v2 = queue[(queue_head + 2) % queue_capacity];
Vertex __attribute__((aligned(32))) v2 = queue[(queue_head + 2) % queue_capacity];
_glClipEdge(&v2, v0, &a);
_glClipEdge(v1, &v2, &b);
a.flags = GPU_CMD_VERTEX;
b.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(0), &a); // replace
memcpy_vertex(QUEUE_OFFSET(1), &a); // replace
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
PUSH_VERTEX(&v2); /* Additional vertex */
visible_mask = 15; /* All 4 vertices visible */
_glPerspectiveDivideVertex(&v2, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &v2);
}
break;
case 5: /* First and third vertex were visible */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex v1 = queue[(queue_head + 1) % queue_capacity];
Vertex v2 = queue[(queue_head + 2) % queue_capacity];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex __attribute__((aligned(32))) v2 = queue[(queue_head + 2) % queue_capacity];
_glClipEdge(v0, &v1, &a);
_glClipEdge(&v1, &v2, &b);
_glClipEdge(v0, v1, &a);
_glClipEdge(v1, &v2, &b);
a.flags = GPU_CMD_VERTEX;
b.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(1), &a); // replace
_glPerspectiveDivideVertex(v0, h);
_glPerspectiveDivideVertex(&v2, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, v0);
_glSubmitHeaderOrVertex(d, &a);
uint32_t v2_flags = v2.flags;
v2.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(2), &v2); // replace
_glSubmitHeaderOrVertex(d, &v2);
v2.flags = v2_flags;
PUSH_VERTEX(&b); /* Additional vertex */
PUSH_VERTEX(&v2); /* Additional vertex */
visible_mask = 31; /* All 5 vertices visible */
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &v2);
}
break;
case 3: /* Second and third vertex were visible */
case 6: /* Second and third vertex were visible */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex v1 = queue[(queue_head + 1) % queue_capacity];
Vertex v2 = queue[(queue_head + 2) % queue_capacity];
Vertex __attribute__((aligned(32))) v1 = queue[(queue_head + 1) % queue_capacity];
Vertex __attribute__((aligned(32))) v2 = queue[(queue_head + 2) % queue_capacity];
_glClipEdge(v0, &v1, &a);
_glClipEdge(&v2, v0, &b);
@ -323,42 +353,24 @@ void SceneListSubmit(void* src, int n) {
a.flags = GPU_CMD_VERTEX;
b.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(0), &a); // replace
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
PUSH_VERTEX(&v1); /* Additional vertex */
PUSH_VERTEX(&v2); /* Additional vertex */
visible_mask = 31; /* All 5 vertices visible */
_glPerspectiveDivideVertex(&v1, h);
_glPerspectiveDivideVertex(&v2, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, &v1);
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &v1);
_glSubmitHeaderOrVertex(d, &v2);
}
break;
default:
break;
}
if(glIsLastVertex(current->flags)) {
/* If this was the last vertex in the strip, we need to flush the queue and then
restart it again */
while(visible_mask) {
// There are 3 vertices, so we push the first one
_glPerspectiveDivideVertex(&queue[queue_head], h);
_glSubmitHeaderOrVertex(d, &queue[queue_head]);
queue_head = (queue_head + 1) % queue_capacity;
int mask = (0x80000000 >> __builtin_clz(visible_mask));
visible_mask &= ~mask;
}
} else {
/* Here we need to submit vertices until the visible mask is < 4
* which would mean there are only 2 vertices queued */
while(visible_mask > 3) {
// There are 3 vertices, so we push the first one
_glPerspectiveDivideVertex(&queue[queue_head], h);
_glSubmitHeaderOrVertex(d, &queue[queue_head]);
queue_head = (queue_head + 1) % queue_capacity;
int mask = (0x80000000 >> __builtin_clz(visible_mask));
visible_mask &= ~mask;
}
}
counter--;
}
}

View File

@ -4,6 +4,7 @@
#include <cstdio>
#include <cmath>
#include <stdexcept>
#include <cassert>
#define SQ_BASE_ADDRESS 0
#define SPAN_SORT_CFG 0
@ -141,7 +142,7 @@ void SceneListSubmit(void* src, int n) {
//Set PVR DMA registers
pvrdmacfg[0] = 1;
pvrdmacfg[1] = 0;
pvrdmacfg[1] = 1;
//Set QACR registers
qacr[1] = qacr[0] = 0x11;
@ -154,31 +155,24 @@ void SceneListSubmit(void* src, int n) {
/* The most vertices ever in the queue is 5 (as some clipping operations
* produce and additional couple of vertice, but we add one more so the ring buffer doesn't
* trip over itself (e.g. if tail == head we can guarantee it's empty, not full) */
Vertex __attribute__((aligned(32))) queue[6];
Vertex __attribute__((aligned(32))) queue[4];
const int queue_capacity = sizeof(queue) / sizeof(Vertex);
Vertex* vertex = (Vertex*) src;
uint32_t visible_mask = 0;
uint32_t counter = 0;
#define QUEUE_OFFSET(n) (queue + ((queue_head + (n)) % queue_capacity))
#define PUSH_VERTEX(v) \
do { \
memcpy_vertex(queue + queue_tail, (v)); \
visible_mask = (visible_mask << 1) | ((v)->xyz[2] >= -(v)->w); \
visible_mask = (visible_mask >> 1) | ((v)->xyz[2] >= -(v)->w) << 2; \
assert(visible_mask < 15); \
queue_tail = (queue_tail + 1) % queue_capacity; \
counter++; \
} while(0)
/* Assume first entry is a header */
_glSubmitHeaderOrVertex(d, vertex++);
/* Push first 2 vertices of the strip */
PUSH_VERTEX(vertex);
++vertex;
PUSH_VERTEX(vertex);
++vertex;
n -= 3;
while(n--) {
Vertex* current = vertex;
if(!glIsVertex(vertex->flags)) {
@ -190,31 +184,38 @@ void SceneListSubmit(void* src, int n) {
++vertex;
}
if(counter < 3) {
continue;
}
switch(visible_mask) {
case 0:
queue_head = (queue_head + 1) % queue_capacity;
--counter;
continue;
break;
case 7:
/* All visible, push the first vertex and move on */
_glPerspectiveDivideVertex(&queue[queue_head], h);
_glSubmitHeaderOrVertex(d, &queue[queue_head]);
queue_head = (queue_head + 1) % queue_capacity;
visible_mask >>= 1;
if(glIsLastVertex(current->flags)) {
/* If this was the last vertex in the strip, we clear the
* triangle out */
while(queue_head != queue_tail) {
/* If this was the last vertex in the strip, we need to flush the queue and then
restart it again */
queue_head = (queue_head + 1) % queue_capacity;
counter--;
while(counter--) {
// There are 3 vertices, so we push the first one
_glPerspectiveDivideVertex(&queue[queue_head], h);
_glSubmitHeaderOrVertex(d, &queue[queue_head]);
queue_head = (queue_head + 1) % queue_capacity;
}
visible_mask = 0;
continue;
}
break;
case 4:
case 1:
/* First vertex was visible */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
@ -232,11 +233,14 @@ void SceneListSubmit(void* src, int n) {
cross back*/
b.flags = v2->flags;
// v0 is already at the head of the queue
memcpy_vertex(QUEUE_OFFSET(1), &a); // replace
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
PUSH_VERTEX(&b); /* Additional vertex */
visible_mask = 15; /* All 4 vertices visible */
_glPerspectiveDivideVertex(v0, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, v0);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &b);
}
break;
case 2:
@ -245,56 +249,69 @@ void SceneListSubmit(void* src, int n) {
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex* v2 = &queue[(queue_head + 2) % queue_capacity];
const Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
const Vertex* v2 = &queue[(queue_head + 2) % queue_capacity];
_glClipEdge(v0, v1, &a);
_glClipEdge(v1, v2, &b);
a.flags = GPU_CMD_VERTEX;
b.flags = GPU_CMD_VERTEX_EOL;
memcpy_vertex(QUEUE_OFFSET(0), &a); // replace
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
visible_mask = 7; /* All 3 vertices visible */
_glPerspectiveDivideVertex(v0, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, v0);
_glSubmitHeaderOrVertex(d, &b);
}
break;
case 6: /* First and second vertex were visible */
case 3: /* First and second vertex were visible */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex __attribute__((aligned(32))) v1 = queue[(queue_head + 1) % queue_capacity];
Vertex* v2 = &queue[(queue_head + 2) % queue_capacity];
_glClipEdge(v1, v2, &a);
_glClipEdge(&v1, v2, &a);
_glClipEdge(v2, v0, &b);
a.flags = v2->flags;
b.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
PUSH_VERTEX(v1); /* Additional vertex */
PUSH_VERTEX(&a); /* Additional vertex */
visible_mask = 31; /* All 5 vertices visible */
_glPerspectiveDivideVertex(v0, h);
_glPerspectiveDivideVertex(&v1, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, v0);
_glSubmitHeaderOrVertex(d, &v1);
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &v1);
_glSubmitHeaderOrVertex(d, &a);
}
break;
case 1:
case 4:
/* Third vertex was visible. */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex v2 = queue[(queue_head + 2) % queue_capacity];
Vertex __attribute__((aligned(32))) v2 = queue[(queue_head + 2) % queue_capacity];
_glClipEdge(&v2, v0, &a);
_glClipEdge(v1, &v2, &b);
a.flags = GPU_CMD_VERTEX;
b.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(0), &a); // replace
memcpy_vertex(QUEUE_OFFSET(1), &a); // replace
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
PUSH_VERTEX(&v2); /* Additional vertex */
visible_mask = 15; /* All 4 vertices visible */
_glPerspectiveDivideVertex(&v2, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &v2);
}
break;
case 5: /* First and third vertex were visible */
@ -302,75 +319,59 @@ void SceneListSubmit(void* src, int n) {
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex* v2 = &queue[(queue_head + 2) % queue_capacity];
Vertex __attribute__((aligned(32))) v2 = queue[(queue_head + 2) % queue_capacity];
_glClipEdge(v0, v1, &a);
_glClipEdge(v1, v2, &b);
_glClipEdge(v1, &v2, &b);
a.flags = GPU_CMD_VERTEX;
b.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(1), &a); // replace
_glPerspectiveDivideVertex(v0, h);
_glPerspectiveDivideVertex(&v2, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
uint32_t v2_flags = v2->flags;
v2->flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(2), v2); // replace
v2->flags = v2_flags;
PUSH_VERTEX(&b); /* Additional vertex */
PUSH_VERTEX(v2); /* Additional vertex */
visible_mask = 31; /* All 5 vertices visible */
_glSubmitHeaderOrVertex(d, v0);
_glSubmitHeaderOrVertex(d, &a);
uint32_t v2_flags = v2.flags;
v2.flags = GPU_CMD_VERTEX;
_glSubmitHeaderOrVertex(d, &v2);
v2.flags = v2_flags;
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &v2);
}
break;
case 3: /* Second and third vertex were visible */
case 6: /* Second and third vertex were visible */
{
Vertex __attribute__((aligned(32))) a, b; // Scratch vertices
Vertex* v0 = &queue[queue_head];
Vertex* v1 = &queue[(queue_head + 1) % queue_capacity];
Vertex* v2 = &queue[(queue_head + 2) % queue_capacity];
Vertex __attribute__((aligned(32))) v1 = queue[(queue_head + 1) % queue_capacity];
Vertex __attribute__((aligned(32))) v2 = queue[(queue_head + 2) % queue_capacity];
_glClipEdge(v0, v1, &a);
_glClipEdge(v2, v0, &b);
_glClipEdge(v0, &v1, &a);
_glClipEdge(&v2, v0, &b);
a.flags = GPU_CMD_VERTEX;
b.flags = GPU_CMD_VERTEX;
memcpy_vertex(QUEUE_OFFSET(0), &a); // replace
memcpy_vertex(QUEUE_OFFSET(2), &b); // replace
PUSH_VERTEX(v1); /* Additional vertex */
PUSH_VERTEX(v2); /* Additional vertex */
visible_mask = 31; /* All 5 vertices visible */
_glPerspectiveDivideVertex(&v1, h);
_glPerspectiveDivideVertex(&v2, h);
_glPerspectiveDivideVertex(&a, h);
_glPerspectiveDivideVertex(&b, h);
_glSubmitHeaderOrVertex(d, &a);
_glSubmitHeaderOrVertex(d, &v1);
_glSubmitHeaderOrVertex(d, &b);
_glSubmitHeaderOrVertex(d, &v1);
_glSubmitHeaderOrVertex(d, &v2);
}
break;
default:
break;
}
if(glIsLastVertex(current->flags)) {
/* If this was the last vertex in the strip, we need to flush the queue and then
restart it again */
while(visible_mask) {
// There are 3 vertices, so we push the first one
_glPerspectiveDivideVertex(&queue[queue_head], h);
_glSubmitHeaderOrVertex(d, &queue[queue_head]);
queue_head = (queue_head + 1) % queue_capacity;
/* This bitmask is reversed to the direction it should be, but we're effectively counting
the bits here. Either everything is visible, or it was clipped and so everything is visible */
visible_mask >>= 1;
}
} else {
/* Here we need to submit vertices until the visible mask is < 4
* which would mean there are only 2 vertices queued */
while(visible_mask > 3) {
// There are 3 vertices, so we push the first one
_glPerspectiveDivideVertex(&queue[queue_head], h);
_glSubmitHeaderOrVertex(d, &queue[queue_head]);
queue_head = (queue_head + 1) % queue_capacity;
int mask = (0x80000000 >> __builtin_clz(visible_mask));
visible_mask &= ~mask;
}
}
counter--;
}
}
@ -563,6 +564,27 @@ bool test_clip_case_101() {
return true;
}
bool test_clip_case_111() {
/* 1st and 3rd visible */
sent.clear();
auto data = make_vertices({
{-4.526650, -2.414213, 3.080808, 5.000000},
{0.0, -2.414213, -7.121212, 8.000000},
{4.526650, -2.414213, 3.080808, 5.000000},
});
SceneListSubmit(&data[0], data.size());
check_equal(sent.size(), 4);
check_equal(sent[0].flags, GPU_CMD_POLYHDR);
check_equal(sent[1].flags, GPU_CMD_VERTEX);
check_equal(sent[2].flags, GPU_CMD_VERTEX);
check_equal(sent[3].flags, GPU_CMD_VERTEX_EOL);
return true;
}
bool test_start_behind() {
/* Triangle behind the plane, but the strip continues in front */
sent.clear();
@ -581,6 +603,23 @@ bool test_start_behind() {
return true;
}
bool test_longer_strip() {
sent.clear();
auto data = make_vertices({
{-4.384623, -2.414213, -5.699644, -5.488456},
{4.667572, -2.414213, -5.621354, -5.410322},
{-4.667572, -2.414213, 4.319152, 4.510323},
{4.384623, -2.414213, 4.397442, 4.588456},
{-4.809045, -2.414213, 9.328549, 9.509711},
{4.243149, -2.414213, 9.406840, 9.587846},
});
SceneListSubmit(&data[0], data.size());
return true;
}
int main(int argc, char* argv[]) {
// test_clip_case_000();
test_clip_case_001();
@ -589,9 +628,10 @@ int main(int argc, char* argv[]) {
test_clip_case_110();
test_clip_case_011();
test_clip_case_101();
// test_clip_case_111();
test_clip_case_111();
test_start_behind();
test_longer_strip();
return 0;
}