From af54c96ff4627aa99dc1b25b6632a2781a17bc39 Mon Sep 17 00:00:00 2001 From: Luke Benstead Date: Thu, 6 Sep 2018 19:19:00 +0100 Subject: [PATCH] Implement new culling algorithm, still some issues when GL_CULL_FACE is enabled --- GL/clip.c | 103 ++++++++++++++++++++++++++++++++++++++++++++---------- GL/draw.c | 66 ++++++++++++---------------------- 2 files changed, 106 insertions(+), 63 deletions(-) diff --git a/GL/clip.c b/GL/clip.c index 6a18525..d6368c9 100644 --- a/GL/clip.c +++ b/GL/clip.c @@ -72,6 +72,76 @@ 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 = 0xe0000000; +void clipTriangle(const ClipVertex* vertices, const uint8_t visible, AlignedVector* output) { + uint8_t i, c = 0; + + + uint8_t lastVisible = 255; + ClipVertex* last = NULL; + + for(i = 0; i < 4; ++i) { + uint8_t thisIndex = (i == 3) ? 0 : i; + + ClipVertex next; + next.flags = VERTEX_CMD; + + uint8_t thisVisible = (visible & (1 << (2 - thisIndex))) > 0; + if(i > 0) { + uint8_t lastIndex = (i == 3) ? 2 : thisIndex - 1; + + if(lastVisible < 255 && lastVisible != thisVisible) { + const ClipVertex* v1 = &vertices[lastIndex]; + const ClipVertex* v2 = &vertices[thisIndex]; + float t; + + clipLineToNearZ(v1, v2, &next, &t); + interpolateFloat(v1->w, v2->w, t, &next.w); + 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); + + last = aligned_vector_push_back(output, &next, 1); + last->flags = VERTEX_CMD; + ++c; + } + } + + if(thisVisible && i != 3) { + last = aligned_vector_push_back(output, &vertices[thisIndex], 1); + 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 { + 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 { @@ -130,10 +200,11 @@ void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset) { * be the last */ if(v3->flags == VERTEX_CMD_EOL) { /* Wipe out the triangle */ - *v1 = *v2 = *v3 = *header; - // fprintf(stderr, "A\n"); + markDead(v1); + markDead(v2); + markDead(v3); } else { - *v1 = *header; + markDead(v1); ClipVertex tmp = *v2; *v2 = *v3; *v3 = tmp; @@ -141,7 +212,6 @@ void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset) { triangle = -1; v2->flags = VERTEX_CMD; v3->flags = VERTEX_CMD; - // fprintf(stderr, "B\n"); } break; case 0b100: @@ -169,15 +239,14 @@ void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset) { /* Last triangle in strip so end a vertex early */ if(triangle == 0) { // Wipe out the triangle completely - *v1 = *v2 = *header; + markDead(vertex - 2); + markDead(vertex - 1); } else { // End the strip (vertex - 1)->flags = VERTEX_CMD_EOL; } - /* Reapply the header so a subsequent strip works */ - *vertex = *header; - // fprintf(stderr, "C\n"); + markDead(vertex); } else if(triangle == 0) { /* First triangle in strip, remove first vertex and swap latter two to restart the strip */ @@ -185,13 +254,12 @@ void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset) { *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; + markDead(vertex - 2); + + (vertex - 1)->flags = VERTEX_CMD; + vertex->flags = VERTEX_CMD; triangle = -1; - // fprintf(stderr, "D\n"); } else { ClipVertex* v4 = vertex + 1; @@ -211,10 +279,8 @@ void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset) { (vertex - 1)->flags = VERTEX_CMD_EOL; if(v4->flags == VERTEX_CMD_EOL) { - *vertex = *header; - *v4 = *header; - // fprintf(stderr, "E\n"); - + markDead(vertex); + markDead(v4); } else { /* Swap the next vertices to start a new strip */ ClipVertex tmp = *vertex; @@ -223,7 +289,6 @@ void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset) { vertex->flags = VERTEX_CMD; v4->flags = VERTEX_CMD; - // fprintf(stderr, "F\n"); } i += 1; @@ -236,7 +301,7 @@ void clipTriangleStrip2(AlignedVector* vertices, uint32_t offset) { /* 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); } } diff --git a/GL/draw.c b/GL/draw.c index 5383922..6926eb7 100644 --- a/GL/draw.c +++ b/GL/draw.c @@ -624,48 +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 */ - clipTriangleStrip2(polylist, (output - (ClipVertex*) polylist->data) - 1); + clipTriangleStrip2(polylist, offset); return polylist->size; - - - static AlignedVector* CLIP_BUFFER = NULL; - - /* 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) { @@ -835,12 +797,14 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ profiler_checkpoint("transform"); if(isClippingEnabled()) { - spaceNeeded = clip(&activeList->vector, start, spaceNeeded); - /* - fprintf(stderr, "--------\n"); + uint32_t offset = ((start - 1) - (ClipVertex*) activeList->vector.data); + + /* Uncomment when debugging clipping uint32_t i = 0; - for(i = 0; i < activeList->vector.size; ++i) { + 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); @@ -848,6 +812,20 @@ static void submitVertices(GLenum mode, GLsizei first, GLsizei count, GLenum typ 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");