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