filename | src/pvr2/rendsort.c |
changeset | 318:363935d31859 |
prev | 276:1e594c2804f8 |
next | 319:5392aed6a982 |
author | nkeynes |
date | Tue Jan 23 12:03:57 2007 +0000 (17 years ago) |
permissions | -rw-r--r-- |
last change | Add initial offset color support Honor the "enable fragment alpha" bit |
view | annotate | diff | log | raw |
1 /**
2 * $Id: rendsort.c,v 1.3 2007-01-23 12:03:57 nkeynes Exp $
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 "pvr2/pvr2.h"
20 #include "asic.h"
22 extern char *video_base;
23 extern gboolean pvr2_force_fragment_alpha;
25 #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
26 #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
28 struct pvr_vertex {
29 float x,y,z;
30 uint32_t detail[1];
31 };
33 struct render_triangle {
34 uint32_t *polygon;
35 int vertex_length;
36 float minx,miny,minz;
37 float maxx,maxy,maxz;
38 float *vertexes[3];
39 };
41 #define SENTINEL 0xDEADBEEF
43 /**
44 * Count the number of triangles in the list starting at the given
45 * pvr memory address.
46 */
47 int render_count_triangles( pvraddr_t tile_entry ) {
48 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
49 int count = 0;
50 while(1) {
51 uint32_t entry = *tile_list++;
52 if( entry >> 28 == 0x0F ) {
53 break;
54 } else if( entry >> 28 == 0x0E ) {
55 tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
56 } else if( entry >> 29 == 0x04 ) { /* Triangle array */
57 count += ((entry >> 25) & 0x0F)+1;
58 } else if( entry >> 29 == 0x05 ) { /* Quad array */
59 count += ((((entry >> 25) & 0x0F)+1)<<1);
60 } else { /* Polygon */
61 int i;
62 for( i=0; i<6; i++ ) {
63 if( entry & (0x40000000>>i) ) {
64 count++;
65 }
66 }
67 }
68 }
69 return count;
70 }
72 static void compute_triangle_boxes( struct render_triangle *triangle, int num_triangles )
73 {
74 int i;
75 for( i=0; i<num_triangles; i++ ) {
76 triangle[i].minx = MIN3(triangle[i].vertexes[0][0],triangle[i].vertexes[1][0],triangle[i].vertexes[2][0]);
77 triangle[i].maxx = MAX3(triangle[i].vertexes[0][0],triangle[i].vertexes[1][0],triangle[i].vertexes[2][0]);
78 triangle[i].miny = MIN3(triangle[i].vertexes[0][1],triangle[i].vertexes[1][1],triangle[i].vertexes[2][1]);
79 triangle[i].maxy = MAX3(triangle[i].vertexes[0][1],triangle[i].vertexes[1][1],triangle[i].vertexes[2][1]);
80 triangle[i].minz = MIN3(triangle[i].vertexes[0][2],triangle[i].vertexes[1][2],triangle[i].vertexes[2][2]);
81 triangle[i].maxz = MAX3(triangle[i].vertexes[0][2],triangle[i].vertexes[1][2],triangle[i].vertexes[2][2]);
82 }
83 }
85 void render_extract_triangles( pvraddr_t tile_entry, gboolean cheap_modifier_mode,
86 struct render_triangle *triangles, int num_triangles )
87 {
88 uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
89 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
90 int count = 0;
91 while(1) {
92 uint32_t entry = *tile_list++;
93 if( entry >> 28 == 0x0F ) {
94 break;
95 } else if( entry >> 28 == 0x0E ) {
96 tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
97 } else {
98 uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
99 int is_modified = entry & 0x01000000;
100 int vertex_length = (entry >> 21) & 0x07;
101 int context_length = 3;
102 if( is_modified && !cheap_modifier_mode ) {
103 context_length = 5;
104 vertex_length *= 2 ;
105 }
106 vertex_length += 3;
108 if( (entry & 0xE0000000) == 0x80000000 ) {
109 /* Triangle(s) */
110 int strip_count = ((entry >> 25) & 0x0F)+1;
111 int polygon_length = 3 * vertex_length + context_length;
112 int i;
113 for( i=0; i<strip_count; i++ ) {
114 float *vertex = (float *)(polygon+context_length);
115 triangles[count].polygon = polygon;
116 triangles[count].vertex_length = vertex_length;
117 triangles[count].vertexes[0] = vertex;
118 vertex+=vertex_length;
119 triangles[count].vertexes[1] = vertex;
120 vertex+=vertex_length;
121 triangles[count].vertexes[2] = vertex;
122 polygon += polygon_length;
123 count++;
124 }
125 } else if( (entry & 0xE0000000) == 0xA0000000 ) {
126 /* Sprite(s) */
127 int strip_count = ((entry >> 25) & 0x0F)+1;
128 int polygon_length = 4 * vertex_length + context_length;
129 int i;
130 for( i=0; i<strip_count; i++ ) {
131 float *vertex = (float *)(polygon+context_length);
132 triangles[count].polygon = polygon;
133 triangles[count].vertex_length = vertex_length;
134 triangles[count].vertexes[0] = vertex;
135 vertex+=vertex_length;
136 triangles[count].vertexes[1] = vertex;
137 vertex+=vertex_length;
138 triangles[count].vertexes[2] = vertex;
139 count++;
140 /* Preserve face direction */
141 triangles[count].polygon = polygon;
142 triangles[count].vertex_length = vertex_length;
143 triangles[count].vertexes[0] = vertex;
144 triangles[count].vertexes[1] = vertex - vertex_length;
145 triangles[count].vertexes[2] = vertex + vertex_length;
146 count++;
147 polygon += polygon_length;
148 }
149 } else {
150 /* Polygon */
151 int i, first=-1, last = -1;
152 float *vertex = (float *)polygon+context_length;
153 for( i=0; i<6; i++ ) {
154 if( entry & (0x40000000>>i) ) {
155 triangles[count].polygon = polygon;
156 triangles[count].vertex_length = vertex_length;
157 if( i&1 ) {
158 triangles[count].vertexes[0] = vertex + vertex_length;
159 triangles[count].vertexes[1] = vertex;
160 triangles[count].vertexes[2] = vertex + (vertex_length<<1);
161 } else {
162 triangles[count].vertexes[0] = vertex;
163 triangles[count].vertexes[1] = vertex + vertex_length;
164 triangles[count].vertexes[2] = vertex + (vertex_length<<1);
165 }
166 count++;
167 }
168 vertex += vertex_length;
169 }
170 }
171 }
172 }
173 if( count != num_triangles ) {
174 ERROR( "Extracted triangles do not match expected count!" );
175 }
176 }
178 void render_triangles( struct render_triangle *triangles, int num_triangles,
179 int render_mode )
180 {
181 int i,j, k, m = 0;
182 for( i=0; i<num_triangles; i++ ) {
183 render_set_context( triangles[i].polygon, render_mode );
184 if( render_mode == RENDER_FULLMOD ) {
185 m = (triangles[i].vertex_length - 3)/2;
186 }
188 glBegin( GL_TRIANGLE_STRIP );
190 for( j=0; j<3; j++ ) {
191 uint32_t *vertexes = (uint32_t *)triangles[i].vertexes[j];
192 float *vertexf = (float *)vertexes;
193 uint32_t argb;
194 k = m + 3;
195 if( POLY1_TEXTURED(*triangles[i].polygon) ) {
196 if( POLY1_UV16(*triangles[i].polygon) ) {
197 glTexCoord2f( halftofloat(vertexes[k]>>16),
198 halftofloat(vertexes[k]) );
199 k++;
200 } else {
201 glTexCoord2f( vertexf[k], vertexf[k+1] );
202 k+=2;
203 }
204 }
205 argb = vertexes[k++];
206 if( pvr2_force_fragment_alpha ) {
207 glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
208 (GLubyte)argb, 0xFF );
209 } else {
210 glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8),
211 (GLubyte)argb, (GLubyte)(argb >> 24) );
212 }
214 if( POLY1_SPECULAR(*triangles[i].polygon) ) {
215 uint32_t spec = vertexes[k];
216 glSecondaryColor3ubEXT( (GLubyte)(spec >> 16), (GLubyte)(spec >> 8),
217 (GLubyte)spec );
218 }
219 glVertex3f( vertexf[0], vertexf[1], vertexf[2] );
220 }
221 glEnd();
222 }
225 }
227 int compare_triangles( void *a, void *b )
228 {
229 struct render_triangle *tri1 = a;
230 struct render_triangle *tri2 = b;
231 if( tri1->minz < tri2->minz ) {
232 return -1;
233 } else if( tri1->minz > tri2->minz ) {
234 return 1;
235 } else {
236 return 0;
237 }
238 }
240 void sort_triangles( struct render_triangle *triangles, int num_triangles )
241 {
242 qsort( triangles, num_triangles, sizeof(struct render_triangle), compare_triangles );
243 }
245 void render_autosort_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode )
246 {
247 int num_triangles = render_count_triangles(tile_entry);
248 if( num_triangles == 0 ) {
249 return; /* nothing to do */
250 } else if( num_triangles == 1 ) { /* Triangle can hardly overlap with itself */
251 render_tile( tile_entry, render_mode, cheap_modifier_mode );
252 } else { /* Ooh boy here we go... */
253 struct render_triangle triangles[num_triangles+1];
254 triangles[num_triangles].polygon = (void *)SENTINEL;
255 render_extract_triangles(tile_entry, cheap_modifier_mode, triangles, num_triangles);
256 compute_triangle_boxes(triangles, num_triangles);
257 sort_triangles( triangles, num_triangles );
258 render_triangles(triangles, num_triangles, render_mode);
259 if( triangles[num_triangles].polygon != (void *)SENTINEL ) {
260 fprintf( stderr, "Triangle overflow in render_autosort_tile!" );
261 }
262 }
263 }
.