revision 876:78cd32021472
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 876:78cd32021472 |
parent | 875:2147174fb320 |
child | 877:8331f4aa3616 |
author | nkeynes |
date | Thu Oct 16 04:46:33 2008 +0000 (15 years ago) |
Enhance triangle sort to be a little more precise
1.1 --- a/src/pvr2/rendsort.c Tue Oct 14 08:44:37 2008 +00001.2 +++ b/src/pvr2/rendsort.c Thu Oct 16 04:46:33 2008 +00001.3 @@ -24,11 +24,14 @@1.5 #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )1.6 #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )1.7 +#define EPSILON 0.00011.9 struct sort_triangle {1.10 struct polygon_struct *poly;1.11 int triangle_num; // triangle number in the poly, from 01.12 - float maxz;1.13 + /* plane equation */1.14 + float mx, my, mz, d;1.15 + float bounds[6]; /* x1,x2,y1,y2,z1,z2 */1.16 };1.18 #define SENTINEL 0xDEADBEEF1.19 @@ -37,7 +40,7 @@1.20 * Count the number of triangles in the list starting at the given1.21 * pvr memory address.1.22 */1.23 -int sort_count_triangles( pvraddr_t tile_entry ) {1.24 +static int sort_count_triangles( pvraddr_t tile_entry ) {1.25 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);1.26 int count = 0;1.27 while(1) {1.28 @@ -62,6 +65,35 @@1.29 return count;1.30 }1.32 +static void sort_add_triangle( struct sort_triangle *triangle, struct polygon_struct *poly, int index )1.33 +{1.34 + struct vertex_struct *vertexes = &pvr2_scene.vertex_array[poly->vertex_index+index];1.35 + triangle->poly = poly;1.36 + triangle->triangle_num = index;1.37 +1.38 + /* Compute triangle bounding-box */1.39 + triangle->bounds[0] = MIN3(vertexes[0].x,vertexes[1].x,vertexes[2].x);1.40 + triangle->bounds[1] = MAX3(vertexes[0].x,vertexes[1].x,vertexes[2].x);1.41 + triangle->bounds[2] = MIN3(vertexes[0].y,vertexes[1].y,vertexes[2].y);1.42 + triangle->bounds[3] = MAX3(vertexes[0].y,vertexes[1].y,vertexes[2].y);1.43 + triangle->bounds[4] = MIN3(vertexes[0].z,vertexes[1].z,vertexes[2].z);1.44 + triangle->bounds[5] = MAX3(vertexes[0].z,vertexes[1].z,vertexes[2].z);1.45 +1.46 + /* Compute plane equation */1.47 + float sx = vertexes[1].x - vertexes[0].x;1.48 + float sy = vertexes[1].y - vertexes[0].y;1.49 + float sz = vertexes[1].z - vertexes[0].z;1.50 + float tx = vertexes[2].x - vertexes[0].x;1.51 + float ty = vertexes[2].y - vertexes[0].y;1.52 + float tz = vertexes[2].z - vertexes[0].z;1.53 + triangle->mx = sy*tz - sz*ty;1.54 + triangle->my = sz*tx - sx*tz;1.55 + triangle->mz = sx*ty - sy*tx;1.56 + triangle->d = -vertexes[0].x*triangle->mx -1.57 + vertexes[0].y*triangle->my -1.58 + vertexes[0].z*triangle->mz;1.59 +}1.60 +1.61 /**1.62 * Extract a triangle list from the tile (basically indexes into the polygon list, plus1.63 * computing maxz while we go through it1.64 @@ -86,12 +118,8 @@1.65 poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];1.66 while( strip_count > 0 ) {1.67 assert( poly != NULL );1.68 - for( i=0; i<poly->vertex_count-2; i++ ) {1.69 - triangles[count].poly = poly;1.70 - triangles[count].triangle_num = i;1.71 - triangles[count].maxz = MAX3( pvr2_scene.vertex_array[poly->vertex_index+i].z,1.72 - pvr2_scene.vertex_array[poly->vertex_index+i+1].z,1.73 - pvr2_scene.vertex_array[poly->vertex_index+i+2].z );1.74 + for( i=0; i<poly->vertex_count-2; i++ ) {1.75 + sort_add_triangle( &triangles[count], poly, i );1.76 count++;1.77 }1.78 poly = poly->next;1.79 @@ -103,11 +131,7 @@1.80 poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];1.81 for( i=0; i<6; i++ ) {1.82 if( entry & (0x40000000>>i) ) {1.83 - triangles[count].poly = poly;1.84 - triangles[count].triangle_num = i;1.85 - triangles[count].maxz = MAX3( pvr2_scene.vertex_array[poly->vertex_index+i].z,1.86 - pvr2_scene.vertex_array[poly->vertex_index+i+1].z,1.87 - pvr2_scene.vertex_array[poly->vertex_index+i+2].z );1.88 + sort_add_triangle( &triangles[count], poly, i );1.89 count++;1.90 }1.91 }1.92 @@ -117,38 +141,110 @@1.94 }1.96 -void sort_render_triangles( struct sort_triangle *triangles, int num_triangles,1.97 - int render_mode )1.98 +void sort_render_triangles( struct sort_triangle **triangles, int num_triangles )1.99 {1.100 int i;1.101 for( i=0; i<num_triangles; i++ ) {1.102 - struct polygon_struct *poly = triangles[i].poly;1.103 + struct polygon_struct *poly = triangles[i]->poly;1.104 if( poly->tex_id != -1 ) {1.105 glBindTexture(GL_TEXTURE_2D, poly->tex_id);1.106 }1.107 render_set_context( poly->context, GL_GEQUAL );1.108 glDepthMask(GL_FALSE);1.109 /* Fix cull direction */1.110 - if( triangles[i].triangle_num & 1 ) {1.111 + if( triangles[i]->triangle_num & 1 ) {1.112 glCullFace(GL_FRONT);1.113 } else {1.114 glCullFace(GL_BACK);1.115 }1.117 - glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index + triangles[i].triangle_num, 3 );1.118 + glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index + triangles[i]->triangle_num, 3 );1.119 }1.120 }1.122 -int compare_triangles( const void *a, const void *b )1.123 +static int sort_triangle_compare( const void *a, const void *b )1.124 {1.125 const struct sort_triangle *tri1 = a;1.126 const struct sort_triangle *tri2 = b;1.127 - return tri2->maxz - tri1->maxz;1.128 + if( tri1->bounds[5] <= tri2->bounds[4] )1.129 + return 1; /* tri1 is entirely under tri2 */1.130 + else if( tri2->bounds[5] <= tri1->bounds[4] )1.131 + return -1; /* tri2 is entirely under tri1 */1.132 + else if( tri1->bounds[1] <= tri2->bounds[0] ||1.133 + tri2->bounds[1] <= tri1->bounds[0] ||1.134 + tri1->bounds[3] <= tri2->bounds[2] ||1.135 + tri2->bounds[3] <= tri1->bounds[2] )1.136 + return 0; /* tri1 and tri2 don't actually overlap at all */1.137 + else {1.138 + struct vertex_struct *tri1v = &pvr2_scene.vertex_array[tri1->poly->vertex_index + tri1->triangle_num];1.139 + struct vertex_struct *tri2v = &pvr2_scene.vertex_array[tri2->poly->vertex_index + tri2->triangle_num];1.140 + float v[3];1.141 + int i;1.142 + for( i=0; i<3; i++ ) {1.143 + v[i] = tri1->mx * tri2v[i].x + tri1->my * tri2v[i].y + tri1->mz * tri2v[i].z + tri1->d;1.144 + if( v[i] > -EPSILON && v[i] < EPSILON ) v[i] = 0;1.145 + }1.146 + if( v[0] == 0 && v[1] == 0 && v[2] == 0 ) {1.147 + return 0; /* coplanar */1.148 + }1.149 + if( (v[0] >=0 && v[1] >= 0 && v[2] >= 0) ||1.150 + (v[0] <= 0 && v[1] <= 0 && v[2] <= 0) ) {1.151 + /* Tri is on one side of the plane. Pick an arbitrary point to determine which side */1.152 + float t1z = -(tri1->mx * tri2v[0].x + tri1->my * tri2v[0].y + tri1->d) / tri1->mz;1.153 + return tri2v[0].z - t1z;1.154 + }1.155 +1.156 + /* If the above test failed, then tri2 intersects tri1's plane. This1.157 + * doesn't necessarily mean the triangles intersect (although they may).1.158 + * For now just return 0, and come back to this later as it's a fairly1.159 + * uncommon case in practice.1.160 + */1.161 + return 0;1.162 + }1.163 }1.165 -void sort_triangles( struct sort_triangle *triangles, int num_triangles )1.166 +/**1.167 + * This is pretty much a standard merge sort (Unfortunately can't depend on1.168 + * the system to provide one. Note we can't use quicksort here - the sort1.169 + * must be stable to preserve the order of coplanar triangles.1.170 + */1.171 +static void sort_triangles( struct sort_triangle **triangles, int num_triangles, struct sort_triangle **out )1.172 {1.173 - qsort( triangles, num_triangles, sizeof(struct sort_triangle), compare_triangles );1.174 + if( num_triangles > 2 ) {1.175 + int l = num_triangles>>1, r=num_triangles-l, i=0,j=0;1.176 + struct sort_triangle *left[l];1.177 + struct sort_triangle *right[r];1.178 + sort_triangles( triangles, l, left );1.179 + sort_triangles( triangles+l, r, right );1.180 +1.181 + /* Merge */1.182 + while(1) {1.183 + if( sort_triangle_compare(left[i], right[j]) <= 0 ) {1.184 + *out++ = left[i++];1.185 + if( i == l ) {1.186 + memcpy( out, &right[j], (r-j)*sizeof(struct sort_triangle *) );1.187 + break;1.188 + }1.189 + } else {1.190 + *out++ = right[j++];1.191 + if( j == r ) {1.192 + memcpy( out, &left[i], (l-i)*sizeof(struct sort_triangle *) );1.193 + break;1.194 + }1.195 + }1.196 + }1.197 + } else if( num_triangles == 2 ) {1.198 + if( sort_triangle_compare(triangles[0], triangles[1]) <= 0 ) {1.199 + out[0] = triangles[0];1.200 + out[1] = triangles[1];1.201 + } else {1.202 + struct sort_triangle *tmp = triangles[0];1.203 + out[0] = triangles[1];1.204 + out[1] = tmp;1.205 + }1.206 + } else {1.207 + out[0] = triangles[0];1.208 + }1.209 }1.211 void render_autosort_tile( pvraddr_t tile_entry, int render_mode )1.212 @@ -159,14 +255,17 @@1.213 } else if( num_triangles == 1 ) { /* Triangle can hardly overlap with itself */1.214 gl_render_tilelist(tile_entry, GL_LEQUAL);1.215 } else { /* Ooh boy here we go... */1.216 + int i;1.217 struct sort_triangle triangles[num_triangles+1];1.218 - // Reserve space for num_triangles / 2 * 4 vertexes (maximum possible number of1.219 - // quad vertices)1.220 + struct sort_triangle *triangle_order[num_triangles+1];1.221 triangles[num_triangles].poly = (void *)SENTINEL;1.222 + for( i=0; i<num_triangles; i++ ) {1.223 + triangle_order[i] = &triangles[i];1.224 + }1.225 int extracted_triangles = sort_extract_triangles(tile_entry, triangles);1.226 assert( extracted_triangles == num_triangles );1.227 - sort_triangles( triangles, num_triangles );1.228 - sort_render_triangles(triangles, num_triangles, render_mode);1.229 + sort_triangles( triangle_order, num_triangles, triangle_order );1.230 + sort_render_triangles(triangle_order, num_triangles);1.231 glCullFace(GL_BACK);1.232 assert( triangles[num_triangles].poly == (void *)SENTINEL );1.233 }
.