commit
d94ee888dc
478
GL/clip.c
478
GL/clip.c
|
@ -72,280 +72,236 @@ 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 clipTriangle(const ClipVertex* vertices, const uint8_t visible, AlignedVector* output) __attribute__((optimize("fast-math")));
|
||||||
|
void clipTriangle(const ClipVertex* vertices, const uint8_t visible, AlignedVector* output) {
|
||||||
|
uint8_t i, c = 0;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void clipTriangleStrip(const ClipVertex* vertices, const unsigned int count, AlignedVector* outBuffer) __attribute__((optimize("fast-math")));
|
uint8_t lastVisible = 255;
|
||||||
void clipTriangleStrip(const ClipVertex* vertices, const unsigned int count, AlignedVector* outBuffer) {
|
ClipVertex* last = NULL;
|
||||||
|
|
||||||
/* Clipping triangle strips is *hard* this is the algorithm we follow:
|
for(i = 0; i < 4; ++i) {
|
||||||
*
|
uint8_t thisIndex = (i == 3) ? 0 : i;
|
||||||
* - Treat each triangle in the strip individually.
|
|
||||||
* - If we find a triangle that needs clipping, treat it in isolation.
|
|
||||||
* - End the strip at the triangle
|
|
||||||
* - Generate a new single-triangle strip for it
|
|
||||||
* - Begin a new strip for the remainder of the strip
|
|
||||||
*
|
|
||||||
* There is probably more efficient way but there are so many different cases to handle that it's
|
|
||||||
* difficult to even write them down!
|
|
||||||
*/
|
|
||||||
|
|
||||||
uint32_t i;
|
ClipVertex next;
|
||||||
uint32_t stripCount = 2; /* The number of vertices in the source strip so far */
|
next.flags = VERTEX_CMD;
|
||||||
|
|
||||||
ClipVertex* thisVertex = vertices + 1;
|
uint8_t thisVisible = (visible & (1 << (2 - thisIndex))) > 0;
|
||||||
|
if(i > 0) {
|
||||||
|
uint8_t lastIndex = (i == 3) ? 2 : thisIndex - 1;
|
||||||
|
|
||||||
for(i = 2; i < count; ++i) {
|
if(lastVisible < 255 && lastVisible != thisVisible) {
|
||||||
++thisVertex;
|
const ClipVertex* v1 = &vertices[lastIndex];
|
||||||
|
const ClipVertex* v2 = &vertices[thisIndex];
|
||||||
|
float t;
|
||||||
|
|
||||||
if(stripCount < 2) {
|
clipLineToNearZ(v1, v2, &next, &t);
|
||||||
stripCount++;
|
interpolateFloat(v1->w, v2->w, t, &next.w);
|
||||||
continue;
|
interpolateVec3(v1->nxyz, v2->nxyz, t, next.nxyz);
|
||||||
}
|
interpolateVec2(v1->uv, v2->uv, t, next.uv);
|
||||||
|
interpolateVec2(v1->st, v2->st, t, next.st);
|
||||||
|
interpolateColour(v1->bgra, v2->bgra, t, next.bgra);
|
||||||
|
|
||||||
const ClipVertex* sourceTriangle[3] = {
|
last = aligned_vector_push_back(output, &next, 1);
|
||||||
thisVertex - 2,
|
last->flags = VERTEX_CMD;
|
||||||
thisVertex - 1,
|
++c;
|
||||||
thisVertex
|
|
||||||
};
|
|
||||||
|
|
||||||
/* If we're on an odd vertex, we need to swap the order of the first two vertices, as that's what
|
|
||||||
* triangle strips do */
|
|
||||||
uint32_t swap = stripCount > 2 && (stripCount % 2 != 0);
|
|
||||||
const ClipVertex* v1 = swap ? sourceTriangle[1] : sourceTriangle[0];
|
|
||||||
const ClipVertex* v2 = swap ? sourceTriangle[0] : sourceTriangle[1];
|
|
||||||
const ClipVertex* v3 = sourceTriangle[2];
|
|
||||||
|
|
||||||
uint32_t visible = ((v1->w > 0) ? 4 : 0) | ((v2->w > 0) ? 2 : 0) | ((v3->w > 0) ? 1 : 0);
|
|
||||||
uint32_t startOfStrip = (i == 2) || (outBuffer->size > 2 && ((ClipVertex*) aligned_vector_back(outBuffer))->flags == VERTEX_CMD_EOL);
|
|
||||||
|
|
||||||
/* All visible, we're fine! */
|
|
||||||
if(visible == 0b111) {
|
|
||||||
if(startOfStrip) {
|
|
||||||
aligned_vector_push_back(outBuffer, v1, 1);
|
|
||||||
aligned_vector_push_back(outBuffer, v2, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
aligned_vector_push_back(outBuffer, v3, 1);
|
|
||||||
} else if(visible == 0b000) {
|
|
||||||
/* Do nothing */
|
|
||||||
continue;
|
|
||||||
} else if(visible == 0b100) {
|
|
||||||
/* Only the first vertex is visible */
|
|
||||||
float t1 = 0, t2 = 0;
|
|
||||||
|
|
||||||
ClipVertex output[3];
|
|
||||||
|
|
||||||
clipLineToNearZ(v1, v2, &output[1], &t1);
|
|
||||||
clipLineToNearZ(v1, v3, &output[2], &t2);
|
|
||||||
|
|
||||||
interpolateFloat(v1->w, v2->w, t1, &output[1].w);
|
|
||||||
interpolateFloat(v1->w, v3->w, t2, &output[2].w);
|
|
||||||
|
|
||||||
output[0] = *v1;
|
|
||||||
|
|
||||||
/* Interpolate normals */
|
|
||||||
interpolateVec3(v1->nxyz, v2->nxyz, t1, output[1].nxyz);
|
|
||||||
interpolateVec3(v1->nxyz, v3->nxyz, t2, output[2].nxyz);
|
|
||||||
|
|
||||||
/* Interpolate texcoords */
|
|
||||||
interpolateVec2(v1->uv, v2->uv, t1, output[1].uv);
|
|
||||||
interpolateVec2(v1->uv, v3->uv, t2, output[2].uv);
|
|
||||||
|
|
||||||
interpolateVec2(v1->st, v2->st, t1, output[1].st);
|
|
||||||
interpolateVec2(v1->st, v3->st, t2, output[2].st);
|
|
||||||
|
|
||||||
interpolateColour(v1->bgra, v2->bgra, t1, output[1].bgra);
|
|
||||||
interpolateColour(v1->bgra, v3->bgra, t2, output[2].bgra);
|
|
||||||
|
|
||||||
output[0].flags = VERTEX_CMD;
|
|
||||||
output[1].flags = VERTEX_CMD;
|
|
||||||
output[2].flags = VERTEX_CMD_EOL;
|
|
||||||
|
|
||||||
aligned_vector_push_back(outBuffer, output, 3);
|
|
||||||
} else if(visible == 0b010) {
|
|
||||||
/* Only the second vertex is visible */
|
|
||||||
|
|
||||||
float t1 = 0, t2 = 0;
|
|
||||||
|
|
||||||
ClipVertex output[3];
|
|
||||||
|
|
||||||
clipLineToNearZ(v2, v1, &output[0], &t1);
|
|
||||||
clipLineToNearZ(v2, v3, &output[2], &t2);
|
|
||||||
|
|
||||||
interpolateFloat(v2->w, v1->w, t1, &output[0].w);
|
|
||||||
interpolateFloat(v2->w, v3->w, t2, &output[2].w);
|
|
||||||
|
|
||||||
output[1] = *v2;
|
|
||||||
|
|
||||||
/* Interpolate normals */
|
|
||||||
interpolateVec3(v2->nxyz, v1->nxyz, t1, output[0].nxyz);
|
|
||||||
interpolateVec3(v2->nxyz, v3->nxyz, t2, output[2].nxyz);
|
|
||||||
|
|
||||||
/* Interpolate texcoords */
|
|
||||||
interpolateVec2(v2->uv, v1->uv, t1, output[0].uv);
|
|
||||||
interpolateVec2(v2->uv, v3->uv, t2, output[2].uv);
|
|
||||||
|
|
||||||
interpolateVec2(v2->st, v1->st, t1, output[0].st);
|
|
||||||
interpolateVec2(v2->st, v3->st, t2, output[2].st);
|
|
||||||
|
|
||||||
interpolateColour(v2->bgra, v1->bgra, t1, output[0].bgra);
|
|
||||||
interpolateColour(v2->bgra, v3->bgra, t2, output[2].bgra);
|
|
||||||
|
|
||||||
output[0].flags = VERTEX_CMD;
|
|
||||||
output[1].flags = VERTEX_CMD;
|
|
||||||
output[2].flags = VERTEX_CMD_EOL;
|
|
||||||
|
|
||||||
aligned_vector_push_back(outBuffer, output, 3);
|
|
||||||
} else if(visible == 0b001) {
|
|
||||||
/* Only the third vertex is visible */
|
|
||||||
|
|
||||||
float t1 = 0, t2 = 0;
|
|
||||||
|
|
||||||
ClipVertex output[3];
|
|
||||||
|
|
||||||
clipLineToNearZ(v3, v1, &output[0], &t1);
|
|
||||||
clipLineToNearZ(v3, v2, &output[1], &t2);
|
|
||||||
|
|
||||||
interpolateFloat(v3->w, v1->w, t1, &output[0].w);
|
|
||||||
interpolateFloat(v3->w, v2->w, t2, &output[1].w);
|
|
||||||
|
|
||||||
output[2] = *v3;
|
|
||||||
|
|
||||||
/* Interpolate normals */
|
|
||||||
interpolateVec3(v3->nxyz, v1->nxyz, t1, output[0].nxyz);
|
|
||||||
interpolateVec3(v3->nxyz, v2->nxyz, t2, output[1].nxyz);
|
|
||||||
|
|
||||||
/* Interpolate texcoords */
|
|
||||||
interpolateVec2(v3->uv, v1->uv, t1, output[0].uv);
|
|
||||||
interpolateVec2(v3->uv, v2->uv, t2, output[1].uv);
|
|
||||||
|
|
||||||
interpolateVec2(v3->st, v1->st, t1, output[0].st);
|
|
||||||
interpolateVec2(v3->st, v2->st, t2, output[1].st);
|
|
||||||
|
|
||||||
interpolateColour(v3->bgra, v1->bgra, t1, output[0].bgra);
|
|
||||||
interpolateColour(v3->bgra, v2->bgra, t2, output[1].bgra);
|
|
||||||
|
|
||||||
output[0].flags = VERTEX_CMD;
|
|
||||||
output[1].flags = VERTEX_CMD;
|
|
||||||
output[2].flags = VERTEX_CMD_EOL;
|
|
||||||
|
|
||||||
aligned_vector_push_back(outBuffer, output, 3);
|
|
||||||
} else if(visible == 0b110) {
|
|
||||||
/* Third vertex isn't visible */
|
|
||||||
|
|
||||||
float t1 = 0, t2 = 0;
|
|
||||||
|
|
||||||
ClipVertex output[4];
|
|
||||||
|
|
||||||
clipLineToNearZ(v2, v3, &output[2], &t1);
|
|
||||||
clipLineToNearZ(v1, v3, &output[3], &t2);
|
|
||||||
|
|
||||||
interpolateFloat(v2->w, v3->w, t1, &output[2].w);
|
|
||||||
interpolateFloat(v1->w, v3->w, t2, &output[3].w);
|
|
||||||
|
|
||||||
output[0] = *v1;
|
|
||||||
output[1] = *v2;
|
|
||||||
|
|
||||||
/* Interpolate normals */
|
|
||||||
interpolateVec3(v2->nxyz, v3->nxyz, t1, output[2].nxyz);
|
|
||||||
interpolateVec3(v1->nxyz, v3->nxyz, t2, output[3].nxyz);
|
|
||||||
|
|
||||||
/* Interpolate texcoords */
|
|
||||||
interpolateVec2(v2->uv, v3->uv, t1, output[2].uv);
|
|
||||||
interpolateVec2(v1->uv, v3->uv, t2, output[3].uv);
|
|
||||||
|
|
||||||
interpolateVec2(v2->st, v3->st, t1, output[2].st);
|
|
||||||
interpolateVec2(v1->st, v3->st, t2, output[3].st);
|
|
||||||
|
|
||||||
interpolateColour(v2->bgra, v3->bgra, t1, output[2].bgra);
|
|
||||||
interpolateColour(v1->bgra, v3->bgra, t2, output[3].bgra);
|
|
||||||
|
|
||||||
output[0].flags = VERTEX_CMD;
|
|
||||||
output[1].flags = VERTEX_CMD;
|
|
||||||
output[2].flags = VERTEX_CMD;
|
|
||||||
output[3].flags = VERTEX_CMD_EOL;
|
|
||||||
|
|
||||||
aligned_vector_push_back(outBuffer, output, 4);
|
|
||||||
} else if(visible == 0b011) {
|
|
||||||
/* First vertex isn't visible, so let's clip along the lines to the second and third */
|
|
||||||
float t1 = 0, t2 = 0;
|
|
||||||
|
|
||||||
ClipVertex output[4];
|
|
||||||
|
|
||||||
clipLineToNearZ(v1, v2, &output[0], &t1);
|
|
||||||
clipLineToNearZ(v1, v3, &output[2], &t2);
|
|
||||||
|
|
||||||
interpolateFloat(v1->w, v2->w, t1, &output[0].w);
|
|
||||||
interpolateFloat(v1->w, v3->w, t2, &output[2].w);
|
|
||||||
|
|
||||||
output[1] = *v2;
|
|
||||||
output[3] = *v3;
|
|
||||||
|
|
||||||
/* Interpolate normals */
|
|
||||||
interpolateVec3(v1->nxyz, v2->nxyz, t1, output[0].nxyz);
|
|
||||||
interpolateVec3(v1->nxyz, v3->nxyz, t2, output[2].nxyz);
|
|
||||||
|
|
||||||
/* Interpolate texcoords */
|
|
||||||
interpolateVec2(v1->uv, v2->uv, t1, output[0].uv);
|
|
||||||
interpolateVec2(v1->uv, v3->uv, t2, output[2].uv);
|
|
||||||
|
|
||||||
interpolateVec2(v1->st, v2->st, t1, output[0].st);
|
|
||||||
interpolateVec2(v1->st, v3->st, t2, output[2].st);
|
|
||||||
|
|
||||||
interpolateColour(v1->bgra, v2->bgra, t1, output[0].bgra);
|
|
||||||
interpolateColour(v1->bgra, v3->bgra, t2, output[2].bgra);
|
|
||||||
|
|
||||||
output[0].flags = VERTEX_CMD;
|
|
||||||
output[1].flags = VERTEX_CMD;
|
|
||||||
output[2].flags = VERTEX_CMD;
|
|
||||||
output[3].flags = VERTEX_CMD_EOL;
|
|
||||||
|
|
||||||
aligned_vector_push_back(outBuffer, output, 4);
|
|
||||||
} else if(visible == 0b101) {
|
|
||||||
/* Second vertex isn't visible */
|
|
||||||
float t1 = 0, t2 = 0;
|
|
||||||
|
|
||||||
ClipVertex output[4];
|
|
||||||
|
|
||||||
clipLineToNearZ(v1, v2, &output[1], &t1);
|
|
||||||
clipLineToNearZ(v3, v2, &output[3], &t2);
|
|
||||||
|
|
||||||
interpolateFloat(v1->w, v2->w, t1, &output[1].w);
|
|
||||||
interpolateFloat(v3->w, v2->w, t2, &output[3].w);
|
|
||||||
|
|
||||||
output[0] = *v1;
|
|
||||||
output[2] = *v3;
|
|
||||||
|
|
||||||
/* Interpolate normals */
|
|
||||||
interpolateVec3(v1->nxyz, v2->nxyz, t1, output[1].nxyz);
|
|
||||||
interpolateVec3(v3->nxyz, v2->nxyz, t2, output[3].nxyz);
|
|
||||||
|
|
||||||
/* Interpolate texcoords */
|
|
||||||
interpolateVec2(v1->uv, v2->uv, t1, output[1].uv);
|
|
||||||
interpolateVec2(v3->uv, v2->uv, t2, output[3].uv);
|
|
||||||
|
|
||||||
interpolateVec2(v1->st, v2->st, t1, output[1].st);
|
|
||||||
interpolateVec2(v3->st, v2->st, t2, output[3].st);
|
|
||||||
|
|
||||||
interpolateColour(v1->bgra, v2->bgra, t1, output[1].bgra);
|
|
||||||
interpolateColour(v3->bgra, v2->bgra, t2, output[3].bgra);
|
|
||||||
|
|
||||||
output[0].flags = VERTEX_CMD;
|
|
||||||
output[1].flags = VERTEX_CMD;
|
|
||||||
output[2].flags = VERTEX_CMD;
|
|
||||||
output[3].flags = VERTEX_CMD_EOL;
|
|
||||||
|
|
||||||
aligned_vector_push_back(outBuffer, output, 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If this vertex was the last in the list, reset the stripCount */
|
if(thisVisible && i != 3) {
|
||||||
if(thisVertex->flags == VERTEX_CMD_EOL) {
|
last = aligned_vector_push_back(output, &vertices[thisIndex], 1);
|
||||||
stripCount = 0;
|
last->flags = VERTEX_CMD;
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
|
||||||
|
lastVisible = thisVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(last) {
|
||||||
|
if(c == 4) {
|
||||||
|
/* Convert to two triangles */
|
||||||
|
ClipVertex newVerts[3];
|
||||||
|
newVerts[0] = *(last - 3);
|
||||||
|
newVerts[1] = *(last - 1);
|
||||||
|
newVerts[2] = *(last);
|
||||||
|
|
||||||
|
(last - 1)->flags = VERTEX_CMD_EOL;
|
||||||
|
newVerts[0].flags = VERTEX_CMD;
|
||||||
|
newVerts[1].flags = VERTEX_CMD;
|
||||||
|
newVerts[2].flags = VERTEX_CMD_EOL;
|
||||||
|
|
||||||
|
aligned_vector_resize(output, output->size - 1);
|
||||||
|
aligned_vector_push_back(output, newVerts, 3);
|
||||||
} else {
|
} else {
|
||||||
stripCount++;
|
last->flags = VERTEX_CMD_EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void markDead(ClipVertex* vert) {
|
||||||
|
vert->flags = VERTEX_CMD_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 */
|
||||||
|
markDead(v1);
|
||||||
|
markDead(v2);
|
||||||
|
markDead(v3);
|
||||||
|
} else {
|
||||||
|
markDead(v1);
|
||||||
|
ClipVertex tmp = *v2;
|
||||||
|
*v2 = *v3;
|
||||||
|
*v3 = tmp;
|
||||||
|
|
||||||
|
triangle = -1;
|
||||||
|
v2->flags = VERTEX_CMD;
|
||||||
|
v3->flags = VERTEX_CMD;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
markDead(vertex - 2);
|
||||||
|
markDead(vertex - 1);
|
||||||
|
} else {
|
||||||
|
// End the strip
|
||||||
|
(vertex - 1)->flags = VERTEX_CMD_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
markDead(vertex);
|
||||||
|
} 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;
|
||||||
|
|
||||||
|
markDead(vertex - 2);
|
||||||
|
|
||||||
|
(vertex - 1)->flags = VERTEX_CMD;
|
||||||
|
vertex->flags = VERTEX_CMD;
|
||||||
|
|
||||||
|
triangle = -1;
|
||||||
|
} 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) {
|
||||||
|
markDead(vertex);
|
||||||
|
markDead(v4);
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, clip all the triangles and append them to the output */
|
||||||
|
for(i = 0; i < CLIP_COUNT; ++i) {
|
||||||
|
clipTriangle(TO_CLIP[i].vertex, TO_CLIP[i].visible, vertices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
73
GL/draw.c
73
GL/draw.c
|
@ -624,45 +624,10 @@ static void transform(ClipVertex* output, const GLsizei count) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static GLsizei clip(AlignedVector* polylist, ClipVertex* output, const GLsizei count) {
|
static GLsizei clip(AlignedVector* polylist, uint32_t offset, const GLsizei count) {
|
||||||
/* Perform clipping, generating new vertices as necessary */
|
/* Perform clipping, generating new vertices as necessary */
|
||||||
|
clipTriangleStrip2(polylist, offset);
|
||||||
static AlignedVector* CLIP_BUFFER = NULL;
|
return polylist->size;
|
||||||
|
|
||||||
/* First entry into this, allocate the clip buffer */
|
|
||||||
if(!CLIP_BUFFER) {
|
|
||||||
CLIP_BUFFER = (AlignedVector*) malloc(sizeof(AlignedVector));
|
|
||||||
aligned_vector_init(CLIP_BUFFER, sizeof(ClipVertex));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we allocate roughly enough space */
|
|
||||||
aligned_vector_reserve(CLIP_BUFFER, count * 1.5);
|
|
||||||
|
|
||||||
/* Start from empty */
|
|
||||||
aligned_vector_resize(CLIP_BUFFER, 0);
|
|
||||||
|
|
||||||
/* Now perform clipping! */
|
|
||||||
clipTriangleStrip(output, count, CLIP_BUFFER);
|
|
||||||
|
|
||||||
/* Calculate the new required size for the poly list. This is the original size
|
|
||||||
* plus the difference in size between the original vertex count and the clip buffer
|
|
||||||
* count */
|
|
||||||
GLsizei newSize = polylist->size + (CLIP_BUFFER->size - count);
|
|
||||||
|
|
||||||
/* Copy the clip buffer over the vertices */
|
|
||||||
aligned_vector_resize(polylist, newSize);
|
|
||||||
|
|
||||||
GLsizei i = CLIP_BUFFER->size;
|
|
||||||
ClipVertex* dst = output;
|
|
||||||
ClipVertex* src = (ClipVertex*) CLIP_BUFFER->data;
|
|
||||||
while(i--) {
|
|
||||||
*dst = *src;
|
|
||||||
++dst;
|
|
||||||
++src;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the new vertex count */
|
|
||||||
return CLIP_BUFFER->size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mat_transform3(const float* xyz, const float* xyzOut, const uint32_t count, const uint32_t inStride, const uint32_t outStride) {
|
static void mat_transform3(const float* xyz, const float* xyzOut, const uint32_t count, const uint32_t inStride, const uint32_t outStride) {
|
||||||
|
@ -832,7 +797,35 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ
|
||||||
profiler_checkpoint("transform");
|
profiler_checkpoint("transform");
|
||||||
|
|
||||||
if(isClippingEnabled()) {
|
if(isClippingEnabled()) {
|
||||||
spaceNeeded = clip(&activeList->vector, start, spaceNeeded);
|
|
||||||
|
uint32_t offset = ((start - 1) - (ClipVertex*) activeList->vector.data);
|
||||||
|
|
||||||
|
/* Uncomment when debugging clipping
|
||||||
|
uint32_t i = 0;
|
||||||
|
fprintf(stderr, "=========\n");
|
||||||
|
|
||||||
|
for(i = offset; 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));
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
spaceNeeded = clip(&activeList->vector, offset, spaceNeeded);
|
||||||
|
|
||||||
|
/* Uncomment when debugging clipping
|
||||||
|
fprintf(stderr, "--------\n");
|
||||||
|
for(i = offset; 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 +873,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