Search
lxdream.org :: lxdream/src/pvr2/rendsort.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendsort.c
changeset 653:3202ff01d48e
prev561:533f6b478071
next669:ab344e42bca9
author nkeynes
date Sat Apr 19 02:39:37 2008 +0000 (16 years ago)
permissions -rw-r--r--
last change Centralize gl ext checks in glutil.c
view annotate diff log raw
     1 /**
     2  * $Id$
     3  *
     4  * PVR2 renderer routines for depth sorted polygons
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    18 #include <sys/time.h>
    19 #include <string.h>
    20 #include <assert.h>
    21 #include "pvr2/pvr2.h"
    22 #include "pvr2/scene.h"
    23 #include "asic.h"
    25 extern char *video_base;
    27 #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
    28 #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
    30 struct sort_triangle {
    31     struct polygon_struct *poly;
    32     int triangle_num; // triangle number in the poly, from 0
    33     float maxz;
    34 };
    36 #define SENTINEL 0xDEADBEEF
    38 /**
    39  * Count the number of triangles in the list starting at the given 
    40  * pvr memory address.
    41  */
    42 int sort_count_triangles( pvraddr_t tile_entry ) {
    43     uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
    44     int count = 0;
    45     while(1) {
    46 	uint32_t entry = *tile_list++;
    47 	if( entry >> 28 == 0x0F ) {
    48 	    break;
    49 	} else if( entry >> 28 == 0x0E ) {
    50 	    tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
    51 	} else if( entry >> 29 == 0x04 ) { /* Triangle array */
    52 	    count += ((entry >> 25) & 0x0F)+1;
    53 	} else if( entry >> 29 == 0x05 ) { /* Quad array */
    54 	    count += ((((entry >> 25) & 0x0F)+1)<<1);
    55 	} else { /* Polygon */
    56 	    int i;
    57 	    for( i=0; i<6; i++ ) {
    58 		if( entry & (0x40000000>>i) ) {
    59 		    count++;
    60 		}
    61 	    }
    62 	}
    63     }
    64     return count;
    65 }
    67 /**
    68  * Extract a triangle list from the tile (basically indexes into the polygon list, plus
    69  * computing maxz while we go through it
    70  */
    71 int sort_extract_triangles( pvraddr_t tile_entry, struct sort_triangle *triangles )
    72 {
    73     uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
    74     int count = 0;
    75     while(1) {
    76 	uint32_t entry = *tile_list++;
    77 	if( entry >> 28 == 0x0F ) {
    78 	    break;
    79 	} else if( entry >> 28 == 0x0E ) {
    80 	    tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
    81 	} else {
    82 	    uint32_t poly_addr = entry & 0x000FFFFF;
    83 	    int is_modified = entry & 0x01000000;
    84 	    int vertex_length = (entry >> 21) & 0x07;
    85 	    int context_length = 3;
    86 	    if( is_modified && pvr2_scene.full_shadow ) {
    87 		context_length = 5;
    88 		vertex_length *= 2 ;
    89 	    }
    90 	    vertex_length += 3;
    92 	    if( (entry & 0xE0000000) == 0x80000000 ) {
    93 		/* Triangle(s) */
    94 		int strip_count = ((entry >> 25) & 0x0F)+1;
    95 		int polygon_length = 3 * vertex_length + context_length;
    96 		int i;
    97 		for( i=0; i<strip_count; i++ ) {
    98 		    struct polygon_struct *poly = pvr2_scene.buf_to_poly_map[poly_addr];
    99 		    triangles[count].poly = poly;
   100 		    triangles[count].triangle_num = 0;
   101 		    triangles[count].maxz = MAX3( pvr2_scene.vertex_array[poly->vertex_index].z,
   102 						  pvr2_scene.vertex_array[poly->vertex_index+1].z,
   103 						  pvr2_scene.vertex_array[poly->vertex_index+2].z );
   104 		    poly_addr += polygon_length;
   105 		    count++;
   106 		}
   107 	    } else if( (entry & 0xE0000000) == 0xA0000000 ) {
   108 		/* Quad(s) */
   109 		int strip_count = ((entry >> 25) & 0x0F)+1;
   110 		int polygon_length = 4 * vertex_length + context_length;
   111 		int i;
   112 		for( i=0; i<strip_count; i++ ) {
   113 		    struct polygon_struct *poly = pvr2_scene.buf_to_poly_map[poly_addr];
   114 		    triangles[count].poly = poly;
   115 		    triangles[count].triangle_num = 0;
   116 		    triangles[count].maxz = MAX3( pvr2_scene.vertex_array[poly->vertex_index].z,
   117 						  pvr2_scene.vertex_array[poly->vertex_index+1].z,
   118 						  pvr2_scene.vertex_array[poly->vertex_index+2].z );
   119 		    count++;
   120 		    triangles[count].poly = poly;
   121 		    triangles[count].triangle_num = 1;
   122 		    triangles[count].maxz = MAX3( pvr2_scene.vertex_array[poly->vertex_index+1].z,
   123 						  pvr2_scene.vertex_array[poly->vertex_index+2].z,
   124 						  pvr2_scene.vertex_array[poly->vertex_index+3].z );
   125 		    count++;
   126 		    poly_addr += polygon_length;
   127 		}
   128 	    } else {
   129 		/* Polygon */
   130 		int i;
   131 		struct polygon_struct *poly = pvr2_scene.buf_to_poly_map[poly_addr];
   132 		for( i=0; i<6; i++ ) {
   133 		    if( entry & (0x40000000>>i) ) {
   134 			triangles[count].poly = poly;
   135 			triangles[count].triangle_num = i;
   136 			triangles[count].maxz = MAX3( pvr2_scene.vertex_array[poly->vertex_index+i].z,
   137 						      pvr2_scene.vertex_array[poly->vertex_index+i+1].z,
   138 						      pvr2_scene.vertex_array[poly->vertex_index+i+2].z );
   139 			count++;
   140 		    }
   141 		}
   142 	    }
   143 	}
   144     }
   145     return count;
   146 }
   148 void sort_render_triangles( struct sort_triangle *triangles, int num_triangles,
   149 			    int render_mode )
   150 {
   151     int i;
   152     for( i=0; i<num_triangles; i++ ) {
   153 	struct polygon_struct *poly = triangles[i].poly;
   154 	if( poly->tex_id != -1 ) {
   155 	    glBindTexture(GL_TEXTURE_2D, poly->tex_id);
   156 	}
   157 	render_set_context( poly->context, RENDER_NORMAL );
   158 	glDepthMask(GL_FALSE);
   159 	glDepthFunc(GL_GEQUAL);
   160 	/* Fix cull direction */
   161 	if( triangles[i].triangle_num & 1 ) {
   162 	    glCullFace(GL_FRONT);
   163 	} else {
   164 	    glCullFace(GL_BACK);
   165 	}
   167 	glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index + triangles[i].triangle_num, 3 );
   168     }
   169 }
   171 int compare_triangles( const void *a, const void *b ) 
   172 {
   173     const struct sort_triangle *tri1 = a;
   174     const struct sort_triangle *tri2 = b;
   175     return tri2->maxz - tri1->maxz;
   176 }
   178 void sort_triangles( struct sort_triangle *triangles, int num_triangles )
   179 {
   180     qsort( triangles, num_triangles, sizeof(struct sort_triangle), compare_triangles );
   181 } 
   183 void render_autosort_tile( pvraddr_t tile_entry, int render_mode ) 
   184 {
   185     int num_triangles = sort_count_triangles(tile_entry);
   186     if( num_triangles == 0 ) {
   187 	return; /* nothing to do */
   188     } else if( num_triangles == 1 ) { /* Triangle can hardly overlap with itself */
   189 	gl_render_tilelist(tile_entry);
   190     } else { /* Ooh boy here we go... */
   191 	struct sort_triangle triangles[num_triangles+1];
   192 	// Reserve space for num_triangles / 2 * 4 vertexes (maximum possible number of
   193 	// quad vertices)
   194 	triangles[num_triangles].poly = (void *)SENTINEL;
   195 	int extracted_triangles = sort_extract_triangles(tile_entry, triangles);
   196 	assert( extracted_triangles == num_triangles );
   197 	sort_triangles( triangles, num_triangles );
   198 	sort_render_triangles(triangles, num_triangles, render_mode);
   199 	glCullFace(GL_BACK);
   200 	assert( triangles[num_triangles].poly == (void *)SENTINEL );
   201     }
   202 }
.