nkeynes@222 | 1 | /**
|
nkeynes@561 | 2 | * $Id$
|
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@645 | 19 | #include <string.h>
|
nkeynes@645 | 20 | #include <assert.h>
|
nkeynes@222 | 21 | #include "pvr2/pvr2.h"
|
nkeynes@645 | 22 | #include "pvr2/scene.h"
|
nkeynes@222 | 23 | #include "asic.h"
|
nkeynes@222 | 24 |
|
nkeynes@222 | 25 | extern char *video_base;
|
nkeynes@222 | 26 |
|
nkeynes@222 | 27 | #define MIN3( a,b,c ) ((a) < (b) ? ( (a) < (c) ? (a) : (c) ) : ((b) < (c) ? (b) : (c)) )
|
nkeynes@222 | 28 | #define MAX3( a,b,c ) ((a) > (b) ? ( (a) > (c) ? (a) : (c) ) : ((b) > (c) ? (b) : (c)) )
|
nkeynes@222 | 29 |
|
nkeynes@645 | 30 | struct sort_triangle {
|
nkeynes@645 | 31 | struct polygon_struct *poly;
|
nkeynes@645 | 32 | int triangle_num; // triangle number in the poly, from 0
|
nkeynes@645 | 33 | float minz;
|
nkeynes@222 | 34 | };
|
nkeynes@222 | 35 |
|
nkeynes@318 | 36 | #define SENTINEL 0xDEADBEEF
|
nkeynes@318 | 37 |
|
nkeynes@222 | 38 | /**
|
nkeynes@222 | 39 | * Count the number of triangles in the list starting at the given
|
nkeynes@222 | 40 | * pvr memory address.
|
nkeynes@222 | 41 | */
|
nkeynes@645 | 42 | int sort_count_triangles( pvraddr_t tile_entry ) {
|
nkeynes@222 | 43 | uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
|
nkeynes@222 | 44 | int count = 0;
|
nkeynes@222 | 45 | while(1) {
|
nkeynes@222 | 46 | uint32_t entry = *tile_list++;
|
nkeynes@222 | 47 | if( entry >> 28 == 0x0F ) {
|
nkeynes@222 | 48 | break;
|
nkeynes@222 | 49 | } else if( entry >> 28 == 0x0E ) {
|
nkeynes@222 | 50 | tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
|
nkeynes@222 | 51 | } else if( entry >> 29 == 0x04 ) { /* Triangle array */
|
nkeynes@222 | 52 | count += ((entry >> 25) & 0x0F)+1;
|
nkeynes@222 | 53 | } else if( entry >> 29 == 0x05 ) { /* Quad array */
|
nkeynes@222 | 54 | count += ((((entry >> 25) & 0x0F)+1)<<1);
|
nkeynes@222 | 55 | } else { /* Polygon */
|
nkeynes@222 | 56 | int i;
|
nkeynes@222 | 57 | for( i=0; i<6; i++ ) {
|
nkeynes@222 | 58 | if( entry & (0x40000000>>i) ) {
|
nkeynes@222 | 59 | count++;
|
nkeynes@222 | 60 | }
|
nkeynes@222 | 61 | }
|
nkeynes@222 | 62 | }
|
nkeynes@222 | 63 | }
|
nkeynes@222 | 64 | return count;
|
nkeynes@222 | 65 | }
|
nkeynes@222 | 66 |
|
nkeynes@645 | 67 | /**
|
nkeynes@645 | 68 | * Extract a triangle list from the tile (basically indexes into the polygon list, plus
|
nkeynes@645 | 69 | * computing minz while we go through it
|
nkeynes@645 | 70 | */
|
nkeynes@645 | 71 | int sort_extract_triangles( pvraddr_t tile_entry, struct sort_triangle *triangles )
|
nkeynes@222 | 72 | {
|
nkeynes@222 | 73 | uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
|
nkeynes@222 | 74 | int count = 0;
|
nkeynes@222 | 75 | while(1) {
|
nkeynes@222 | 76 | uint32_t entry = *tile_list++;
|
nkeynes@222 | 77 | if( entry >> 28 == 0x0F ) {
|
nkeynes@222 | 78 | break;
|
nkeynes@222 | 79 | } else if( entry >> 28 == 0x0E ) {
|
nkeynes@222 | 80 | tile_list = (uint32_t *)(video_base+(entry&0x007FFFFF));
|
nkeynes@222 | 81 | } else {
|
nkeynes@645 | 82 | uint32_t poly_addr = entry & 0x000FFFFF;
|
nkeynes@222 | 83 | int is_modified = entry & 0x01000000;
|
nkeynes@222 | 84 | int vertex_length = (entry >> 21) & 0x07;
|
nkeynes@222 | 85 | int context_length = 3;
|
nkeynes@645 | 86 | if( is_modified && pvr2_scene.full_shadow ) {
|
nkeynes@222 | 87 | context_length = 5;
|
nkeynes@222 | 88 | vertex_length *= 2 ;
|
nkeynes@222 | 89 | }
|
nkeynes@222 | 90 | vertex_length += 3;
|
nkeynes@222 | 91 |
|
nkeynes@222 | 92 | if( (entry & 0xE0000000) == 0x80000000 ) {
|
nkeynes@222 | 93 | /* Triangle(s) */
|
nkeynes@222 | 94 | int strip_count = ((entry >> 25) & 0x0F)+1;
|
nkeynes@222 | 95 | int polygon_length = 3 * vertex_length + context_length;
|
nkeynes@222 | 96 | int i;
|
nkeynes@222 | 97 | for( i=0; i<strip_count; i++ ) {
|
nkeynes@645 | 98 | struct polygon_struct *poly = pvr2_scene.buf_to_poly_map[poly_addr];
|
nkeynes@645 | 99 | triangles[count].poly = poly;
|
nkeynes@645 | 100 | triangles[count].triangle_num = 0;
|
nkeynes@645 | 101 | triangles[count].minz = MIN3( pvr2_scene.vertex_array[poly->vertex_index].z,
|
nkeynes@645 | 102 | pvr2_scene.vertex_array[poly->vertex_index+1].z,
|
nkeynes@645 | 103 | pvr2_scene.vertex_array[poly->vertex_index+2].z );
|
nkeynes@645 | 104 | poly_addr += polygon_length;
|
nkeynes@222 | 105 | count++;
|
nkeynes@222 | 106 | }
|
nkeynes@222 | 107 | } else if( (entry & 0xE0000000) == 0xA0000000 ) {
|
nkeynes@319 | 108 | /* Quad(s) */
|
nkeynes@276 | 109 | int strip_count = ((entry >> 25) & 0x0F)+1;
|
nkeynes@222 | 110 | int polygon_length = 4 * vertex_length + context_length;
|
nkeynes@222 | 111 | int i;
|
nkeynes@222 | 112 | for( i=0; i<strip_count; i++ ) {
|
nkeynes@645 | 113 | struct polygon_struct *poly = pvr2_scene.buf_to_poly_map[poly_addr];
|
nkeynes@645 | 114 | triangles[count].poly = poly;
|
nkeynes@645 | 115 | triangles[count].triangle_num = 0;
|
nkeynes@645 | 116 | triangles[count].minz = MIN3( pvr2_scene.vertex_array[poly->vertex_index].z,
|
nkeynes@645 | 117 | pvr2_scene.vertex_array[poly->vertex_index+1].z,
|
nkeynes@645 | 118 | pvr2_scene.vertex_array[poly->vertex_index+2].z );
|
nkeynes@222 | 119 | count++;
|
nkeynes@645 | 120 | triangles[count].poly = poly;
|
nkeynes@645 | 121 | triangles[count].triangle_num = 1;
|
nkeynes@645 | 122 | triangles[count].minz = MIN3( pvr2_scene.vertex_array[poly->vertex_index+1].z,
|
nkeynes@645 | 123 | pvr2_scene.vertex_array[poly->vertex_index+2].z,
|
nkeynes@645 | 124 | pvr2_scene.vertex_array[poly->vertex_index+3].z );
|
nkeynes@222 | 125 | count++;
|
nkeynes@645 | 126 | poly_addr += polygon_length;
|
nkeynes@222 | 127 | }
|
nkeynes@222 | 128 | } else {
|
nkeynes@222 | 129 | /* Polygon */
|
nkeynes@429 | 130 | int i;
|
nkeynes@645 | 131 | struct polygon_struct *poly = pvr2_scene.buf_to_poly_map[poly_addr];
|
nkeynes@222 | 132 | for( i=0; i<6; i++ ) {
|
nkeynes@222 | 133 | if( entry & (0x40000000>>i) ) {
|
nkeynes@645 | 134 | triangles[count].poly = poly;
|
nkeynes@645 | 135 | triangles[count].triangle_num = i;
|
nkeynes@645 | 136 | triangles[count].minz = MIN3( pvr2_scene.vertex_array[poly->vertex_index+i].z,
|
nkeynes@645 | 137 | pvr2_scene.vertex_array[poly->vertex_index+i+1].z,
|
nkeynes@645 | 138 | pvr2_scene.vertex_array[poly->vertex_index+i+2].z );
|
nkeynes@222 | 139 | count++;
|
nkeynes@222 | 140 | }
|
nkeynes@222 | 141 | }
|
nkeynes@222 | 142 | }
|
nkeynes@222 | 143 | }
|
nkeynes@222 | 144 | }
|
nkeynes@645 | 145 | return count;
|
nkeynes@222 | 146 | }
|
nkeynes@222 | 147 |
|
nkeynes@645 | 148 | void sort_render_triangles( struct sort_triangle *triangles, int num_triangles,
|
nkeynes@645 | 149 | int render_mode )
|
nkeynes@222 | 150 | {
|
nkeynes@429 | 151 | int i;
|
nkeynes@222 | 152 | for( i=0; i<num_triangles; i++ ) {
|
nkeynes@645 | 153 | struct polygon_struct *poly = triangles[i].poly;
|
nkeynes@645 | 154 | if( poly->tex_id != -1 ) {
|
nkeynes@645 | 155 | glBindTexture(GL_TEXTURE_2D, poly->tex_id);
|
nkeynes@645 | 156 | }
|
nkeynes@645 | 157 | render_set_context( poly->context, RENDER_NORMAL );
|
nkeynes@331 | 158 | glEnable(GL_DEPTH_TEST);
|
nkeynes@331 | 159 | glDepthFunc(GL_GEQUAL);
|
nkeynes@645 | 160 | if( triangles[i].triangle_num & 1 ) {
|
nkeynes@645 | 161 | glCullFace(GL_FRONT);
|
nkeynes@319 | 162 | } else {
|
nkeynes@645 | 163 | glCullFace(GL_BACK);
|
nkeynes@222 | 164 | }
|
nkeynes@645 | 165 | /* Fix cull direction */
|
nkeynes@645 | 166 | glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index + triangles[i].triangle_num, 3 );
|
nkeynes@222 | 167 | }
|
nkeynes@222 | 168 | }
|
nkeynes@222 | 169 |
|
nkeynes@429 | 170 | int compare_triangles( const void *a, const void *b )
|
nkeynes@222 | 171 | {
|
nkeynes@645 | 172 | const struct sort_triangle *tri1 = a;
|
nkeynes@645 | 173 | const struct sort_triangle *tri2 = b;
|
nkeynes@645 | 174 | return tri1->minz - tri2->minz;
|
nkeynes@222 | 175 | }
|
nkeynes@222 | 176 |
|
nkeynes@645 | 177 | void sort_triangles( struct sort_triangle *triangles, int num_triangles )
|
nkeynes@222 | 178 | {
|
nkeynes@645 | 179 | qsort( triangles, num_triangles, sizeof(struct sort_triangle), compare_triangles );
|
nkeynes@222 | 180 | }
|
nkeynes@222 | 181 |
|
nkeynes@222 | 182 | void render_autosort_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode )
|
nkeynes@222 | 183 | {
|
nkeynes@645 | 184 | int num_triangles = sort_count_triangles(tile_entry);
|
nkeynes@222 | 185 | if( num_triangles == 0 ) {
|
nkeynes@222 | 186 | return; /* nothing to do */
|
nkeynes@222 | 187 | } else if( num_triangles == 1 ) { /* Triangle can hardly overlap with itself */
|
nkeynes@645 | 188 | gl_render_tilelist(tile_entry);
|
nkeynes@222 | 189 | } else { /* Ooh boy here we go... */
|
nkeynes@645 | 190 | struct sort_triangle triangles[num_triangles+1];
|
nkeynes@319 | 191 | // Reserve space for num_triangles / 2 * 4 vertexes (maximum possible number of
|
nkeynes@319 | 192 | // quad vertices)
|
nkeynes@645 | 193 | triangles[num_triangles].poly = (void *)SENTINEL;
|
nkeynes@645 | 194 | sort_extract_triangles(tile_entry, triangles);
|
nkeynes@222 | 195 | sort_triangles( triangles, num_triangles );
|
nkeynes@645 | 196 | sort_render_triangles(triangles, num_triangles, render_mode);
|
nkeynes@645 | 197 | glCullFace(GL_BACK);
|
nkeynes@645 | 198 | assert( triangles[num_triangles].poly == (void *)SENTINEL );
|
nkeynes@222 | 199 | }
|
nkeynes@222 | 200 | }
|