Start work on new clipping
This commit is contained in:
parent
2ab606f8dc
commit
3fde2abd3e
118
GL/flush.c
118
GL/flush.c
|
@ -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
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
|
#pragma once
|
||||||
|
#define GLDC_VERSION ""
|
||||||
#define GLDC_VERSION "1.2.0alpha"
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user