Start work on new clipping

This commit is contained in:
Luke Benstead 2020-10-27 13:21:37 +00:00
parent 2ab606f8dc
commit 3fde2abd3e
5 changed files with 202 additions and 40 deletions

View File

@ -9,6 +9,8 @@
#include "profiler.h" #include "profiler.h"
#include "version.h" #include "version.h"
#include "flush.h"
#define TA_SQ_ADDR (unsigned int *)(void *) \ #define TA_SQ_ADDR (unsigned int *)(void *) \
(0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0)) (0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0))
@ -18,13 +20,6 @@ static PolyList TR_LIST;
static const int STRIDE = sizeof(Vertex) / sizeof(GLuint); static const int STRIDE = sizeof(Vertex) / sizeof(GLuint);
typedef struct {
int count;
Vertex* current;
GLboolean current_is_vertex;
} ListIterator;
GL_FORCE_INLINE GLboolean isVertex(const Vertex* vertex) { GL_FORCE_INLINE GLboolean isVertex(const Vertex* vertex) {
return ( return (
vertex->flags == PVR_CMD_VERTEX || vertex->flags == PVR_CMD_VERTEX ||
@ -33,46 +28,101 @@ 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;
return vertex->w >= 0 && vertex->xyz[2] >= -vertex->w; return vertex->w >= 0 && vertex->xyz[2] >= -vertex->w;
} }
static inline ListIterator* next(ListIterator* it) { static Vertex* interpolate_vertex(const Vertex* v0, const Vertex* v1, Vertex* out) {
/* Move the list iterator to the next vertex to /* If v0 is in front of the near plane, and v1 is behind the near plane, this
* submit. Takes care of clipping the triangle strip * generates a vertex *on* the near plane */
* and perspective dividing the vertex before
* returning */
while(--it->count) { return out;
it->current++; }
/* Ignore dead vertices */ GL_FORCE_INLINE ListIterator* header_reset(ListIterator* it, Vertex* header) {
if(it->current->flags == DEAD) { it->it = header;
continue; it->visibility = 0;
it->triangle_count = 0;
return it;
}
GL_FORCE_INLINE Vertex* current_postinc(ListIterator* it) {
if(it->remaining == 0) {
return NULL;
}
it->remaining--;
return it->current++;
}
GL_FORCE_INLINE Vertex* push_stack(ListIterator* it) {
return &it->stack[it->stack_idx++];
}
GL_FORCE_INLINE GLboolean shift(ListIterator* it, Vertex* new_vertex) {
/*
* Shifts in a new vertex, dropping the oldest. If
* new_vertex is NULL it will return GL_FALSE (but still
* shift) */
it->triangle_count++;
if(it->triangle_count > 3) it->triangle_count = 3;
it->triangle[0] = it->triangle[1];
it->triangle[1] = it->triangle[2];
it->triangle[2] = new_vertex;
it->visibility <<= 1;
it->visibility &= 7;
it->visibility += isVisible(new_vertex);
return new_vertex != NULL;
}
ListIterator* next(ListIterator* it) {
if(!isVertex(it->current)) {
return header_reset(it, current_postinc(it));
} else {
/* Make sure we have a full triangle of vertices */
while(it->triangle_count < 3) {
if(!isVertex(it->current)) {
return header_reset(it, current_postinc(it));
}
if(!shift(it, current_postinc(it))) {
/* We reached the end so just
* return the oldest until they're gone */
it->it = it->triangle[0];
return (it->it) ? it : NULL;
}
} }
/* If this is a header, then we submit! */ /* OK, by this point we should have info for a complete triangle
it->current_is_vertex = isVertex(it->current); * including visibility */
switch(it->visibility) {
case B111:
/* Totally visible, return the first vertex */
it->it = it->triangle[0];
return it;
break;
case B100:
/* First visible only */
it->triangle[1] = interpolate_vertex(it->triangle[0], it->triangle[1], push_stack(it));
it->triangle[2] = interpolate_vertex(it->triangle[0], it->triangle[2], push_stack(it));
it->visibility = B111; /* All visible now, yay! */
if(it->current_is_vertex) { assert(isVisible(it->triangle[1]));
return it; assert(isVisible(it->triangle[2]));
it->it = it->triangle[0];
return it;
break;
} }
/* All other vertices are fine */
return it;
} }
return NULL; return NULL;
} }
static inline ListIterator* begin(void* src, int n) { GL_FORCE_INLINE void perspective_divide(Vertex* vertex) {
ListIterator* it = (ListIterator*) malloc(sizeof(ListIterator));
it->count = n;
it->current = (Vertex*) src;
it->current_is_vertex = GL_FALSE;
return (n) ? it : NULL;
}
static inline void perspective_divide(Vertex* vertex) {
float f = MATH_Fast_Invert(vertex->w); float f = MATH_Fast_Invert(vertex->w);
vertex->xyz[0] *= f; vertex->xyz[0] *= f;
vertex->xyz[1] *= f; vertex->xyz[1] *= f;
@ -91,7 +141,7 @@ static void pvr_list_submit(void *src, int n) {
while(it) { while(it) {
__asm__("pref @%0" : : "r"(it->current + 1)); /* prefetch 64 bytes for next loop */ __asm__("pref @%0" : : "r"(it->current + 1)); /* prefetch 64 bytes for next loop */
if(it->current_is_vertex) { if(isVertex(it->current)) {
perspective_divide(it->current); perspective_divide(it->current);
} }

48
GL/flush.h Normal file
View File

@ -0,0 +1,48 @@
#pragma once
#include "private.h"
#define MAX_STACK 3
#define B000 0
#define B111 7
#define B100 4
#define B010 2
#define B001 1
#define B101 5
#define B011 3
#define B110 6
typedef struct {
int remaining;
/* Current position in the source list */
Vertex* current;
/* Vertex to read from (this may not exist in the source list) */
Vertex* it;
/* < 8. Bitmask of the last 3 vertices */
uint8_t visibility;
uint8_t triangle_count;
Vertex* triangle[3];
/* Stack of temporary vertices */
Vertex stack[MAX_STACK];
int8_t stack_idx;
} ListIterator;
GL_FORCE_INLINE ListIterator* begin(void* src, int n) {
ListIterator* it = (ListIterator*) malloc(sizeof(ListIterator));
it->remaining = n;
it->current = (Vertex*) src;
it->stack_idx = -1;
it->triangle_count = 0;
it->visibility = 0;
return (n) ? it : NULL;
}
extern ListIterator* next(ListIterator* it);

View File

@ -1,3 +1,2 @@
#pragma once #pragma once
#define GLDC_VERSION ""
#define GLDC_VERSION "1.2.0alpha"

View File

@ -16,7 +16,6 @@ rm-elf:
test_runner.cpp: test_runner.cpp:
$(shell python3 test_generator.py --output=test_runner.cpp $(TESTS)) $(shell python3 test_generator.py --output=test_runner.cpp $(TESTS))
@echo MY_VAR IS $(TESTS)
test_runner.o: test_runner.cpp test_runner.o: test_runner.cpp

View File

@ -1,14 +1,80 @@
#pragma once #pragma once
#include "../utils/test.h" #include "../utils/test.h"
#include "../GL/flush.h"
namespace { namespace {
struct VertexBuilder {
VertexBuilder& add_header() {
Vertex v;
v.flags = 100; // I dunno what this bit of memory would be
list_.push_back(std::move(v));
}
VertexBuilder& add(float x, float y, float z, float w) {
Vertex v;
v.xyz[0] = x;
v.xyz[1] = y;
v.xyz[2] = z;
v.w = w;
}
std::vector<Vertex> done() {
return list_;
}
private:
std::vector<Vertex> list_;
};
class NearZClippingTests : public gldc::test::GLdcTestCase { class NearZClippingTests : public gldc::test::GLdcTestCase {
public: public:
void test_failure() { void test_clipping_100() {
assert_false(true); VertexBuilder builder;
std::vector<Vertex> list = builder.
add_header().
add(1, 1, 2, 1).
add(1, 0, 2, -1).
add(0, 1, 2, -1).done();
ListIterator* it = begin(&list[0], list.size());
Vertex* v0 = it->current;
assert_is_not_null(v0);
it = next(it);
Vertex* v1 = it->current;
assert_is_not_null(v1);
}
void test_clipping_110() {
}
void test_clipping_111() {
}
void test_clipping_101() {
}
void test_clipping_010() {
}
void test_clipping_001() {
}
void test_clipping_000() {
}
void test_clipping_011() {
} }
}; };