Begin implementing a new clipping algorithm
This commit is contained in:
parent
19491173e5
commit
517d21b487
166
GL/clip.c
166
GL/clip.c
|
@ -72,8 +72,172 @@ static inline void interpolateColour(const uint8_t* v1, const uint8_t* v2, const
|
||||||
const uint32_t VERTEX_CMD_EOL = 0xf0000000;
|
const uint32_t VERTEX_CMD_EOL = 0xf0000000;
|
||||||
const uint32_t VERTEX_CMD = 0xe0000000;
|
const uint32_t VERTEX_CMD = 0xe0000000;
|
||||||
|
|
||||||
void clipTriangleStrip2(const ClipVertex* vertices, const unsigned int count, AlignedVector* outBuffer) {
|
void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset) {
|
||||||
|
/* Room for clipping 16 triangles */
|
||||||
|
typedef struct {
|
||||||
|
ClipVertex vertex[3];
|
||||||
|
uint8_t visible;
|
||||||
|
} Triangle;
|
||||||
|
|
||||||
|
static Triangle TO_CLIP[256];
|
||||||
|
static uint8_t CLIP_COUNT = 0;
|
||||||
|
|
||||||
|
CLIP_COUNT = 0;
|
||||||
|
|
||||||
|
uint32_t i = 0;
|
||||||
|
/* Skip the header */
|
||||||
|
ClipVertex* header = (ClipVertex*) aligned_vector_at(vertices, offset);
|
||||||
|
ClipVertex* vertex = header + 1;
|
||||||
|
|
||||||
|
uint32_t count = vertices->size - offset;
|
||||||
|
|
||||||
|
int32_t triangle = 0;
|
||||||
|
|
||||||
|
/* Start at 3 due to the header */
|
||||||
|
for(i = 3; i < count; ++i, ++triangle) {
|
||||||
|
vertex = aligned_vector_at(vertices, offset + i);
|
||||||
|
|
||||||
|
uint8_t even = (triangle % 2) == 0;
|
||||||
|
ClipVertex* v1 = (even) ? vertex - 2 : vertex - 1;
|
||||||
|
ClipVertex* v2 = (even) ? vertex - 1 : vertex - 2;
|
||||||
|
ClipVertex* v3 = vertex;
|
||||||
|
|
||||||
|
uint8_t visible = ((v1->w > 0) ? 4 : 0) | ((v2->w > 0) ? 2 : 0) | ((v3->w > 0) ? 1 : 0);
|
||||||
|
|
||||||
|
switch(visible) {
|
||||||
|
case 0b111:
|
||||||
|
/* All visible? Do nothing */
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case 0b000:
|
||||||
|
/*
|
||||||
|
It is not possible that this is any trangle except the first
|
||||||
|
in a strip. That's because:
|
||||||
|
- It's either the first triangle submitted
|
||||||
|
- A previous triangle must have been clipped and the strip
|
||||||
|
restarted behind the plane
|
||||||
|
|
||||||
|
So, we effectively reboot the strip. We mark the first vertex
|
||||||
|
as the end (so it's ignored) then mark the next two as the
|
||||||
|
start of a new strip. Then if the next triangle crosses
|
||||||
|
back into view, we clip correctly. This will potentially
|
||||||
|
result in a bunch of pointlessly submitted vertices.
|
||||||
|
|
||||||
|
FIXME: Skip submitting those verts
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Even though this is always the first in the strip, it can also
|
||||||
|
* be the last */
|
||||||
|
if(v3->flags == VERTEX_CMD_EOL) {
|
||||||
|
/* Wipe out the triangle */
|
||||||
|
*v1 = *v2 = *v3 = *header;
|
||||||
|
// fprintf(stderr, "A\n");
|
||||||
|
} else {
|
||||||
|
*v1 = *header;
|
||||||
|
ClipVertex tmp = *v2;
|
||||||
|
*v2 = *v3;
|
||||||
|
*v3 = tmp;
|
||||||
|
|
||||||
|
triangle = -1;
|
||||||
|
v2->flags = VERTEX_CMD;
|
||||||
|
v3->flags = VERTEX_CMD;
|
||||||
|
// fprintf(stderr, "B\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0b100:
|
||||||
|
case 0b010:
|
||||||
|
case 0b001:
|
||||||
|
case 0b101:
|
||||||
|
case 0b011:
|
||||||
|
case 0b110:
|
||||||
|
/* Store the triangle for clipping */
|
||||||
|
TO_CLIP[CLIP_COUNT].vertex[0] = *v1;
|
||||||
|
TO_CLIP[CLIP_COUNT].vertex[1] = *v2;
|
||||||
|
TO_CLIP[CLIP_COUNT].vertex[2] = *v3;
|
||||||
|
TO_CLIP[CLIP_COUNT].visible = visible;
|
||||||
|
++CLIP_COUNT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
OK so here's the clever bit. If any triangle except
|
||||||
|
the first or last needs clipping, then the next one does aswell
|
||||||
|
(you can't draw a plane through a single triangle in the middle of a
|
||||||
|
strip, only 2+). This means we can clip in pairs which frees up two
|
||||||
|
vertices in the middle of the strip, which is exactly the space
|
||||||
|
we need to restart the triangle strip after the next triangle
|
||||||
|
*/
|
||||||
|
if(v3->flags == VERTEX_CMD_EOL) {
|
||||||
|
/* Last triangle in strip so end a vertex early */
|
||||||
|
if(triangle == 0) {
|
||||||
|
// Wipe out the triangle completely
|
||||||
|
*v1 = *v2 = *header;
|
||||||
|
} else {
|
||||||
|
// End the strip
|
||||||
|
(vertex - 1)->flags = VERTEX_CMD_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reapply the header so a subsequent strip works */
|
||||||
|
*vertex = *header;
|
||||||
|
// fprintf(stderr, "C\n");
|
||||||
|
} else if(triangle == 0) {
|
||||||
|
/* First triangle in strip, remove first vertex and swap latter two
|
||||||
|
to restart the strip */
|
||||||
|
ClipVertex tmp = *v2;
|
||||||
|
*v2 = *v3;
|
||||||
|
*v3 = tmp;
|
||||||
|
|
||||||
|
/* We simulate removing the vertex by duplicating the header in v1 */
|
||||||
|
*v1 = *header;
|
||||||
|
v2->flags = VERTEX_CMD;
|
||||||
|
v3->flags = VERTEX_CMD;
|
||||||
|
|
||||||
|
triangle = -1;
|
||||||
|
// fprintf(stderr, "D\n");
|
||||||
|
} else {
|
||||||
|
ClipVertex* v4 = vertex + 1;
|
||||||
|
|
||||||
|
TO_CLIP[CLIP_COUNT].vertex[0] = *v3;
|
||||||
|
TO_CLIP[CLIP_COUNT].vertex[1] = *v2;
|
||||||
|
TO_CLIP[CLIP_COUNT].vertex[2] = *v4;
|
||||||
|
|
||||||
|
visible = ((v3->w > 0) ? 4 : 0) | ((v2->w > 0) ? 2 : 0) | ((v4->w > 0) ? 1 : 0);
|
||||||
|
|
||||||
|
TO_CLIP[CLIP_COUNT].visible = visible;
|
||||||
|
++CLIP_COUNT;
|
||||||
|
|
||||||
|
/* Restart strip */
|
||||||
|
triangle = -1;
|
||||||
|
|
||||||
|
/* Mark the second vertex as the end of the strip */
|
||||||
|
(vertex - 1)->flags = VERTEX_CMD_EOL;
|
||||||
|
|
||||||
|
if(v4->flags == VERTEX_CMD_EOL) {
|
||||||
|
*vertex = *header;
|
||||||
|
*v4 = *header;
|
||||||
|
// fprintf(stderr, "E\n");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* Swap the next vertices to start a new strip */
|
||||||
|
ClipVertex tmp = *vertex;
|
||||||
|
*vertex = *v4;
|
||||||
|
*v4 = tmp;
|
||||||
|
|
||||||
|
vertex->flags = VERTEX_CMD;
|
||||||
|
v4->flags = VERTEX_CMD;
|
||||||
|
// fprintf(stderr, "F\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, clip all the triangles and append them to the output */
|
||||||
|
for(i = 0; i < CLIP_COUNT; ++i) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clipTriangleStrip(const ClipVertex* vertices, const unsigned int count, AlignedVector* outBuffer) __attribute__((optimize("fast-math")));
|
void clipTriangleStrip(const ClipVertex* vertices, const unsigned int count, AlignedVector* outBuffer) __attribute__((optimize("fast-math")));
|
||||||
|
|
|
@ -41,6 +41,7 @@ typedef struct {
|
||||||
|
|
||||||
void clipLineToNearZ(const ClipVertex* v1, const ClipVertex* v2, ClipVertex* vout, float* t);
|
void clipLineToNearZ(const ClipVertex* v1, const ClipVertex* v2, ClipVertex* vout, float* t);
|
||||||
void clipTriangleStrip(const ClipVertex* vertices, const unsigned int count, AlignedVector* outBuffer);
|
void clipTriangleStrip(const ClipVertex* vertices, const unsigned int count, AlignedVector* outBuffer);
|
||||||
|
void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
17
GL/draw.c
17
GL/draw.c
|
@ -626,6 +626,9 @@ static void transform(ClipVertex* output, const GLsizei count) {
|
||||||
|
|
||||||
static GLsizei clip(AlignedVector* polylist, ClipVertex* output, const GLsizei count) {
|
static GLsizei clip(AlignedVector* polylist, ClipVertex* output, const GLsizei count) {
|
||||||
/* Perform clipping, generating new vertices as necessary */
|
/* Perform clipping, generating new vertices as necessary */
|
||||||
|
clipTriangleStrip2(polylist, (output - (ClipVertex*) polylist->data) - 1);
|
||||||
|
return polylist->size;
|
||||||
|
|
||||||
|
|
||||||
static AlignedVector* CLIP_BUFFER = NULL;
|
static AlignedVector* CLIP_BUFFER = NULL;
|
||||||
|
|
||||||
|
@ -833,6 +836,18 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
|
||||||
|
|
||||||
if(isClippingEnabled()) {
|
if(isClippingEnabled()) {
|
||||||
spaceNeeded = clip(&activeList->vector, start, spaceNeeded);
|
spaceNeeded = clip(&activeList->vector, start, spaceNeeded);
|
||||||
|
|
||||||
|
/*
|
||||||
|
fprintf(stderr, "--------\n");
|
||||||
|
uint32_t i = 0;
|
||||||
|
for(i = 0; i < activeList->vector.size; ++i) {
|
||||||
|
ClipVertex* v = aligned_vector_at(&activeList->vector, i);
|
||||||
|
if(v->flags == 0xe0000000 || v->flags == 0xf0000000) {
|
||||||
|
fprintf(stderr, "(%f, %f, %f) -> %x\n", v->xyz[0], v->xyz[1], v->xyz[2], v->flags);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "%x\n", *((uint32_t*)v));
|
||||||
|
}
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
profiler_checkpoint("clip");
|
profiler_checkpoint("clip");
|
||||||
|
@ -880,7 +895,7 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
|
||||||
GLsizei i = spaceNeeded;
|
GLsizei i = spaceNeeded;
|
||||||
while(i--) {
|
while(i--) {
|
||||||
vertex->uv[0] = vertex->st[0];
|
vertex->uv[0] = vertex->st[0];
|
||||||
vertex->uv[1] = vertex->st[1];
|
vertex->uv[1] = vertex->st[1];
|
||||||
++vertex;
|
++vertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user