nkeynes@222 | 1 | /**
|
nkeynes@276 | 2 | * $Id: rendsort.c,v 1.2 2007-01-12 10:15:06 nkeynes Exp $
|
nkeynes@222 | 3 | *
|
nkeynes@222 | 4 | * PVR2 renderer routines for depth sorted polygons
|
nkeynes@222 | 5 | *
|
nkeynes@222 | 6 | * Copyright (c) 2005 Nathan Keynes.
|
nkeynes@222 | 7 | *
|
nkeynes@222 | 8 | * This program is free software; you can redistribute it and/or modify
|
nkeynes@222 | 9 | * it under the terms of the GNU General Public License as published by
|
nkeynes@222 | 10 | * the Free Software Foundation; either version 2 of the License, or
|
nkeynes@222 | 11 | * (at your option) any later version.
|
nkeynes@222 | 12 | *
|
nkeynes@222 | 13 | * This program is distributed in the hope that it will be useful,
|
nkeynes@222 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nkeynes@222 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nkeynes@222 | 16 | * GNU General Public License for more details.
|
nkeynes@222 | 17 | */
|
nkeynes@222 | 18 | #include <sys/time.h>
|
nkeynes@222 | 19 | #include "pvr2/pvr2.h"
|
nkeynes@222 | 20 | #include "asic.h"
|
nkeynes@222 | 21 |
|
nkeynes@222 | 22 | extern char *video_base;
|
nkeynes@222 | 23 |
|
nkeynes@222 | 24 | #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
|
nkeynes@222 | 25 | #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
|
nkeynes@222 | 26 |
|
nkeynes@222 | 27 | struct pvr_vertex {
|
nkeynes@222 | 28 | float x,y,z;
|
nkeynes@222 | 29 | uint32_t detail[1];
|
nkeynes@222 | 30 | };
|
nkeynes@222 | 31 |
|
nkeynes@222 | 32 | struct render_triangle {
|
nkeynes@222 | 33 | uint32_t *polygon;
|
nkeynes@222 | 34 | int vertex_length;
|
nkeynes@222 | 35 | float minx,miny,minz;
|
nkeynes@222 | 36 | float maxx,maxy,maxz;
|
nkeynes@222 | 37 | float *vertexes[3];
|
nkeynes@222 | 38 | };
|
nkeynes@222 | 39 |
|
nkeynes@222 | 40 | /**
|
nkeynes@222 | 41 | * Count the number of triangles in the list starting at the given
|
nkeynes@222 | 42 | * pvr memory address.
|
nkeynes@222 | 43 | */
|
nkeynes@222 | 44 | int render_count_triangles( pvraddr_t tile_entry ) {
|
nkeynes@222 | 45 | uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
|
nkeynes@222 | 46 | int count = 0;
|
nkeynes@222 | 47 | while(1) {
|
nkeynes@222 | 48 | uint32_t entry = *tile_list++;
|
nkeynes@222 | 49 | if( entry >> 28 == 0x0F ) {
|
nkeynes@222 | 50 | break;
|
nkeynes@222 | 51 | } else if( entry >> 28 == 0x0E ) {
|
nkeynes@222 | 52 | tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
|
nkeynes@222 | 53 | } else if( entry >> 29 == 0x04 ) { /* Triangle array */
|
nkeynes@222 | 54 | count += ((entry >> 25) & 0x0F)+1;
|
nkeynes@222 | 55 | } else if( entry >> 29 == 0x05 ) { /* Quad array */
|
nkeynes@222 | 56 | count += ((((entry >> 25) & 0x0F)+1)<<1);
|
nkeynes@222 | 57 | } else { /* Polygon */
|
nkeynes@222 | 58 | int i;
|
nkeynes@222 | 59 | for( i=0; i<6; i++ ) {
|
nkeynes@222 | 60 | if( entry & (0x40000000>>i) ) {
|
nkeynes@222 | 61 | count++;
|
nkeynes@222 | 62 | }
|
nkeynes@222 | 63 | }
|
nkeynes@222 | 64 | }
|
nkeynes@222 | 65 | }
|
nkeynes@222 | 66 | return count;
|
nkeynes@222 | 67 | }
|
nkeynes@222 | 68 |
|
nkeynes@222 | 69 | static void compute_triangle_boxes( struct render_triangle *triangle, int num_triangles )
|
nkeynes@222 | 70 | {
|
nkeynes@222 | 71 | int i;
|
nkeynes@222 | 72 | for( i=0; i<num_triangles; i++ ) {
|
nkeynes@222 | 73 | triangle[i].minx = MIN3(triangle[i].vertexes[0][0],triangle[i].vertexes[1][0],triangle[i].vertexes[2][0]);
|
nkeynes@222 | 74 | triangle[i].maxx = MAX3(triangle[i].vertexes[0][0],triangle[i].vertexes[1][0],triangle[i].vertexes[2][0]);
|
nkeynes@222 | 75 | triangle[i].miny = MIN3(triangle[i].vertexes[0][1],triangle[i].vertexes[1][1],triangle[i].vertexes[2][1]);
|
nkeynes@222 | 76 | triangle[i].maxy = MAX3(triangle[i].vertexes[0][1],triangle[i].vertexes[1][1],triangle[i].vertexes[2][1]);
|
nkeynes@222 | 77 | triangle[i].minz = MIN3(triangle[i].vertexes[0][2],triangle[i].vertexes[1][2],triangle[i].vertexes[2][2]);
|
nkeynes@222 | 78 | triangle[i].maxz = MAX3(triangle[i].vertexes[0][2],triangle[i].vertexes[1][2],triangle[i].vertexes[2][2]);
|
nkeynes@222 | 79 | }
|
nkeynes@222 | 80 | }
|
nkeynes@222 | 81 |
|
nkeynes@222 | 82 | void render_extract_triangles( pvraddr_t tile_entry, gboolean cheap_modifier_mode,
|
nkeynes@222 | 83 | struct render_triangle *triangles )
|
nkeynes@222 | 84 | {
|
nkeynes@222 | 85 | uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
|
nkeynes@222 | 86 | uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
|
nkeynes@222 | 87 | int count = 0;
|
nkeynes@222 | 88 | while(1) {
|
nkeynes@222 | 89 | uint32_t entry = *tile_list++;
|
nkeynes@222 | 90 | if( entry >> 28 == 0x0F ) {
|
nkeynes@222 | 91 | break;
|
nkeynes@222 | 92 | } else if( entry >> 28 == 0x0E ) {
|
nkeynes@222 | 93 | tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
|
nkeynes@222 | 94 | } else {
|
nkeynes@222 | 95 | uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
|
nkeynes@222 | 96 | int is_modified = entry & 0x01000000;
|
nkeynes@222 | 97 | int vertex_length = (entry >> 21) & 0x07;
|
nkeynes@222 | 98 | int context_length = 3;
|
nkeynes@222 | 99 | if( is_modified && !cheap_modifier_mode ) {
|
nkeynes@222 | 100 | context_length = 5;
|
nkeynes@222 | 101 | vertex_length *= 2 ;
|
nkeynes@222 | 102 | }
|
nkeynes@222 | 103 | vertex_length += 3;
|
nkeynes@222 | 104 |
|
nkeynes@222 | 105 | if( (entry & 0xE0000000) == 0x80000000 ) {
|
nkeynes@222 | 106 | /* Triangle(s) */
|
nkeynes@222 | 107 | int strip_count = ((entry >> 25) & 0x0F)+1;
|
nkeynes@222 | 108 | int polygon_length = 3 * vertex_length + context_length;
|
nkeynes@222 | 109 | int i;
|
nkeynes@222 | 110 | for( i=0; i<strip_count; i++ ) {
|
nkeynes@222 | 111 | float *vertex = (float *)(polygon+context_length);
|
nkeynes@222 | 112 | triangles[count].polygon = polygon;
|
nkeynes@222 | 113 | triangles[count].vertex_length = vertex_length;
|
nkeynes@222 | 114 | triangles[count].vertexes[0] = vertex;
|
nkeynes@222 | 115 | vertex+=vertex_length;
|
nkeynes@222 | 116 | triangles[count].vertexes[1] = vertex;
|
nkeynes@222 | 117 | vertex+=vertex_length;
|
nkeynes@222 | 118 | triangles[count].vertexes[2] = vertex;
|
nkeynes@222 | 119 | polygon += polygon_length;
|
nkeynes@222 | 120 | count++;
|
nkeynes@222 | 121 | }
|
nkeynes@222 | 122 | } else if( (entry & 0xE0000000) == 0xA0000000 ) {
|
nkeynes@222 | 123 | /* Sprite(s) */
|
nkeynes@276 | 124 | int strip_count = ((entry >> 25) & 0x0F)+1;
|
nkeynes@222 | 125 | int polygon_length = 4 * vertex_length + context_length;
|
nkeynes@222 | 126 | int i;
|
nkeynes@222 | 127 | for( i=0; i<strip_count; i++ ) {
|
nkeynes@222 | 128 | float *vertex = (float *)(polygon+context_length);
|
nkeynes@222 | 129 | triangles[count].polygon = polygon;
|
nkeynes@222 | 130 | triangles[count].vertex_length = vertex_length;
|
nkeynes@222 | 131 | triangles[count].vertexes[0] = vertex;
|
nkeynes@222 | 132 | vertex+=vertex_length;
|
nkeynes@222 | 133 | triangles[count].vertexes[1] = vertex;
|
nkeynes@222 | 134 | vertex+=vertex_length;
|
nkeynes@222 | 135 | triangles[count].vertexes[2] = vertex;
|
nkeynes@222 | 136 | count++;
|
nkeynes@222 | 137 | /* Preserve face direction */
|
nkeynes@222 | 138 | triangles[count].polygon = polygon;
|
nkeynes@222 | 139 | triangles[count].vertex_length = vertex_length;
|
nkeynes@222 | 140 | triangles[count].vertexes[0] = vertex;
|
nkeynes@222 | 141 | triangles[count].vertexes[1] = vertex - vertex_length;
|
nkeynes@222 | 142 | triangles[count].vertexes[2] = vertex + vertex_length;
|
nkeynes@222 | 143 | count++;
|
nkeynes@222 | 144 | polygon += polygon_length;
|
nkeynes@222 | 145 | }
|
nkeynes@222 | 146 | } else {
|
nkeynes@222 | 147 | /* Polygon */
|
nkeynes@222 | 148 | int i, first=-1, last = -1;
|
nkeynes@222 | 149 | float *vertex = (float *)polygon+context_length;
|
nkeynes@222 | 150 | for( i=0; i<6; i++ ) {
|
nkeynes@222 | 151 | if( entry & (0x40000000>>i) ) {
|
nkeynes@222 | 152 | triangles[count].polygon = polygon;
|
nkeynes@222 | 153 | triangles[count].vertex_length = vertex_length;
|
nkeynes@222 | 154 | if( i&1 ) {
|
nkeynes@222 | 155 | triangles[count].vertexes[0] = vertex + vertex_length;
|
nkeynes@222 | 156 | triangles[count].vertexes[1] = vertex;
|
nkeynes@222 | 157 | triangles[count].vertexes[2] = vertex + (vertex_length<<1);
|
nkeynes@222 | 158 | } else {
|
nkeynes@222 | 159 | triangles[count].vertexes[0] = vertex;
|
nkeynes@222 | 160 | triangles[count].vertexes[1] = vertex + vertex_length;
|
nkeynes@222 | 161 | triangles[count].vertexes[2] = vertex + (vertex_length<<1);
|
nkeynes@222 | 162 | }
|
nkeynes@222 | 163 | count++;
|
nkeynes@222 | 164 | }
|
nkeynes@222 | 165 | vertex += vertex_length;
|
nkeynes@222 | 166 | }
|
nkeynes@222 | 167 | }
|
nkeynes@222 | 168 | }
|
nkeynes@222 | 169 | }
|
nkeynes@222 | 170 | }
|
nkeynes@222 | 171 |
|
nkeynes@222 | 172 | void render_triangles( struct render_triangle *triangles, int num_triangles,
|
nkeynes@222 | 173 | int render_mode )
|
nkeynes@222 | 174 | {
|
nkeynes@222 | 175 | int i,j, m = 0;
|
nkeynes@222 | 176 | for( i=0; i<num_triangles; i++ ) {
|
nkeynes@222 | 177 | render_set_context( triangles[i].polygon, render_mode );
|
nkeynes@222 | 178 | if( render_mode == RENDER_FULLMOD ) {
|
nkeynes@222 | 179 | m = (triangles[i].vertex_length - 3)/2;
|
nkeynes@222 | 180 | }
|
nkeynes@222 | 181 |
|
nkeynes@222 | 182 | glBegin( GL_TRIANGLE_STRIP );
|
nkeynes@222 | 183 |
|
nkeynes@222 | 184 | for( j=0; j<3; j++ ) {
|
nkeynes@222 | 185 | uint32_t *vertexes = (uint32_t *)triangles[i].vertexes[j];
|
nkeynes@222 | 186 | float *vertexf = (float *)vertexes;
|
nkeynes@222 | 187 | uint32_t argb;
|
nkeynes@222 | 188 | if( POLY1_TEXTURED(*triangles[i].polygon) ) {
|
nkeynes@222 | 189 | if( POLY1_UV16(*triangles[i].polygon) ) {
|
nkeynes@222 | 190 | glTexCoord2f( halftofloat(vertexes[m+3]>>16),
|
nkeynes@222 | 191 | halftofloat(vertexes[m+3]) );
|
nkeynes@222 | 192 | argb = vertexes[m+4];
|
nkeynes@222 | 193 | } else {
|
nkeynes@222 | 194 | glTexCoord2f( vertexf[m+3], vertexf[m+4] );
|
nkeynes@222 | 195 | argb = vertexes[m+5];
|
nkeynes@222 | 196 | }
|
nkeynes@222 | 197 | } else {
|
nkeynes@222 | 198 | argb = vertexes[m+3];
|
nkeynes@222 | 199 | }
|
nkeynes@222 | 200 |
|
nkeynes@222 | 201 | glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
|
nkeynes@222 | 202 | (GLubyte)argb, (GLubyte)(argb >> 24) );
|
nkeynes@222 | 203 | glVertex3f( vertexf[0], vertexf[1], vertexf[2] );
|
nkeynes@222 | 204 | }
|
nkeynes@222 | 205 | glEnd();
|
nkeynes@222 | 206 | }
|
nkeynes@222 | 207 |
|
nkeynes@222 | 208 |
|
nkeynes@222 | 209 | }
|
nkeynes@222 | 210 |
|
nkeynes@222 | 211 | int compare_triangles( void *a, void *b )
|
nkeynes@222 | 212 | {
|
nkeynes@222 | 213 | struct render_triangle *tri1 = a;
|
nkeynes@222 | 214 | struct render_triangle *tri2 = b;
|
nkeynes@222 | 215 | if( tri1->minz < tri2->minz ) {
|
nkeynes@222 | 216 | return -1;
|
nkeynes@222 | 217 | } else if( tri1->minz > tri2->minz ) {
|
nkeynes@222 | 218 | return 1;
|
nkeynes@222 | 219 | } else {
|
nkeynes@222 | 220 | return 0;
|
nkeynes@222 | 221 | }
|
nkeynes@222 | 222 | }
|
nkeynes@222 | 223 |
|
nkeynes@222 | 224 | void sort_triangles( struct render_triangle *triangles, int num_triangles )
|
nkeynes@222 | 225 | {
|
nkeynes@222 | 226 | qsort( triangles, num_triangles, sizeof(struct render_triangle), compare_triangles );
|
nkeynes@222 | 227 | }
|
nkeynes@222 | 228 |
|
nkeynes@222 | 229 | void render_autosort_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode )
|
nkeynes@222 | 230 | {
|
nkeynes@222 | 231 | int num_triangles = render_count_triangles(tile_entry);
|
nkeynes@222 | 232 | if( num_triangles == 0 ) {
|
nkeynes@222 | 233 | return; /* nothing to do */
|
nkeynes@222 | 234 | } else if( num_triangles == 1 ) { /* Triangle can hardly overlap with itself */
|
nkeynes@222 | 235 | render_tile( tile_entry, render_mode, cheap_modifier_mode );
|
nkeynes@222 | 236 | } else { /* Ooh boy here we go... */
|
nkeynes@222 | 237 | struct render_triangle triangles[num_triangles];
|
nkeynes@222 | 238 | render_extract_triangles(tile_entry, cheap_modifier_mode, triangles);
|
nkeynes@222 | 239 | compute_triangle_boxes(triangles, num_triangles);
|
nkeynes@222 | 240 | sort_triangles( triangles, num_triangles );
|
nkeynes@222 | 241 | render_triangles(triangles, num_triangles, render_mode);
|
nkeynes@222 | 242 | }
|
nkeynes@222 | 243 | }
|