Start work on new clipping
This commit is contained in:
parent
2ab606f8dc
commit
3fde2abd3e
114
GL/flush.c
114
GL/flush.c
|
@ -9,6 +9,8 @@
|
|||
#include "profiler.h"
|
||||
#include "version.h"
|
||||
|
||||
#include "flush.h"
|
||||
|
||||
#define TA_SQ_ADDR (unsigned int *)(void *) \
|
||||
(0xe0000000 | (((unsigned long)0x10000000) & 0x03ffffe0))
|
||||
|
||||
|
@ -18,13 +20,6 @@ static PolyList TR_LIST;
|
|||
|
||||
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) {
|
||||
return (
|
||||
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) {
|
||||
if(!vertex) return GL_FALSE;
|
||||
return vertex->w >= 0 && vertex->xyz[2] >= -vertex->w;
|
||||
}
|
||||
|
||||
static inline ListIterator* next(ListIterator* it) {
|
||||
/* Move the list iterator to the next vertex to
|
||||
* submit. Takes care of clipping the triangle strip
|
||||
* and perspective dividing the vertex before
|
||||
* returning */
|
||||
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
|
||||
* generates a vertex *on* the near plane */
|
||||
|
||||
while(--it->count) {
|
||||
it->current++;
|
||||
return out;
|
||||
}
|
||||
|
||||
/* Ignore dead vertices */
|
||||
if(it->current->flags == DEAD) {
|
||||
continue;
|
||||
GL_FORCE_INLINE ListIterator* header_reset(ListIterator* it, Vertex* header) {
|
||||
it->it = header;
|
||||
it->visibility = 0;
|
||||
it->triangle_count = 0;
|
||||
return it;
|
||||
}
|
||||
|
||||
GL_FORCE_INLINE Vertex* current_postinc(ListIterator* it) {
|
||||
if(it->remaining == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If this is a header, then we submit! */
|
||||
it->current_is_vertex = isVertex(it->current);
|
||||
it->remaining--;
|
||||
return it->current++;
|
||||
}
|
||||
|
||||
if(it->current_is_vertex) {
|
||||
return it;
|
||||
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));
|
||||
}
|
||||
|
||||
/* All other vertices are fine */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* OK, by this point we should have info for a complete triangle
|
||||
* 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! */
|
||||
|
||||
assert(isVisible(it->triangle[1]));
|
||||
assert(isVisible(it->triangle[2]));
|
||||
|
||||
it->it = it->triangle[0];
|
||||
return it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline ListIterator* begin(void* src, int n) {
|
||||
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) {
|
||||
GL_FORCE_INLINE void perspective_divide(Vertex* vertex) {
|
||||
float f = MATH_Fast_Invert(vertex->w);
|
||||
vertex->xyz[0] *= f;
|
||||
vertex->xyz[1] *= f;
|
||||
|
@ -91,7 +141,7 @@ static void pvr_list_submit(void *src, int n) {
|
|||
while(it) {
|
||||
__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);
|
||||
}
|
||||
|
||||
|
|
48
GL/flush.h
Normal file
48
GL/flush.h
Normal 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);
|
||||
|
||||
|
|
@ -1,3 +1,2 @@
|
|||
#pragma once
|
||||
|
||||
#define GLDC_VERSION "1.2.0alpha"
|
||||
#define GLDC_VERSION ""
|
||||
|
|
|
@ -16,7 +16,6 @@ rm-elf:
|
|||
|
||||
test_runner.cpp:
|
||||
$(shell python3 test_generator.py --output=test_runner.cpp $(TESTS))
|
||||
@echo MY_VAR IS $(TESTS)
|
||||
|
||||
test_runner.o: test_runner.cpp
|
||||
|
||||
|
|
|
@ -1,14 +1,80 @@
|
|||
#pragma once
|
||||
|
||||
#include "../utils/test.h"
|
||||
|
||||
#include "../GL/flush.h"
|
||||
|
||||
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 {
|
||||
public:
|
||||
void test_failure() {
|
||||
assert_false(true);
|
||||
void test_clipping_100() {
|
||||
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() {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user