filename | src/pvr2/tacore.c |
changeset | 953:f4a156508ad1 |
prev | 801:92b518a2e915 |
next | 1067:d3c00ffccfcd |
author | nkeynes |
date | Thu Jun 25 01:15:25 2009 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Move configuration to .lxdream/lxdreamrc on *nix, Library/Application Support/Lxdream on OS X Create standard directories on first run Add current quick state to config file Refactor quick-state handling into dreamcast.c, and use the save directory |
file | annotate | diff | log | raw |
nkeynes@189 | 1 | /** |
nkeynes@561 | 2 | * $Id$ |
nkeynes@189 | 3 | * |
nkeynes@189 | 4 | * PVR2 Tile Accelerator implementation |
nkeynes@189 | 5 | * |
nkeynes@189 | 6 | * Copyright (c) 2005 Nathan Keynes. |
nkeynes@189 | 7 | * |
nkeynes@189 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@189 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@189 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@189 | 11 | * (at your option) any later version. |
nkeynes@189 | 12 | * |
nkeynes@189 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@189 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@189 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@189 | 16 | * GNU General Public License for more details. |
nkeynes@189 | 17 | */ |
nkeynes@645 | 18 | #include <string.h> |
nkeynes@669 | 19 | #include "lxdream.h" |
nkeynes@677 | 20 | #include "pvr2/pvr2.h" |
nkeynes@677 | 21 | #include "pvr2/pvr2mmio.h" |
nkeynes@189 | 22 | #include "asic.h" |
nkeynes@669 | 23 | #include "dream.h" |
nkeynes@189 | 24 | |
nkeynes@189 | 25 | #define STATE_IDLE 0 |
nkeynes@189 | 26 | #define STATE_IN_LIST 1 |
nkeynes@194 | 27 | #define STATE_IN_POLYGON 2 |
nkeynes@194 | 28 | #define STATE_EXPECT_POLY_BLOCK2 3 |
nkeynes@194 | 29 | #define STATE_EXPECT_VERTEX_BLOCK2 4 |
nkeynes@194 | 30 | #define STATE_ERROR 5 |
nkeynes@189 | 31 | #define STATE_EXPECT_END_VERTEX_BLOCK2 7 |
nkeynes@189 | 32 | |
nkeynes@189 | 33 | #define TA_CMD(i) ( (i) >> 29 ) |
nkeynes@189 | 34 | #define TA_CMD_END_LIST 0 |
nkeynes@189 | 35 | #define TA_CMD_CLIP 1 |
nkeynes@189 | 36 | #define TA_CMD_POLYGON_CONTEXT 4 |
nkeynes@189 | 37 | #define TA_CMD_SPRITE_CONTEXT 5 |
nkeynes@189 | 38 | #define TA_CMD_VERTEX 7 |
nkeynes@189 | 39 | |
nkeynes@189 | 40 | #define TA_LIST_NONE -1 |
nkeynes@189 | 41 | #define TA_LIST_OPAQUE 0 |
nkeynes@189 | 42 | #define TA_LIST_OPAQUE_MOD 1 |
nkeynes@189 | 43 | #define TA_LIST_TRANS 2 |
nkeynes@189 | 44 | #define TA_LIST_TRANS_MOD 3 |
nkeynes@189 | 45 | #define TA_LIST_PUNCH_OUT 4 |
nkeynes@189 | 46 | #define TA_IS_MODIFIER_LIST(list) (list == TA_LIST_OPAQUE_MOD || list == TA_LIST_TRANS_MOD) |
nkeynes@189 | 47 | |
nkeynes@189 | 48 | #define TA_GROW_UP 0 |
nkeynes@189 | 49 | #define TA_GROW_DOWN 1 |
nkeynes@189 | 50 | |
nkeynes@189 | 51 | #define TA_VERTEX_NONE -1 |
nkeynes@189 | 52 | #define TA_VERTEX_PACKED 0x00 |
nkeynes@189 | 53 | #define TA_VERTEX_TEX_PACKED 0x08 |
nkeynes@189 | 54 | #define TA_VERTEX_TEX_SPEC_PACKED 0x0C |
nkeynes@189 | 55 | #define TA_VERTEX_TEX_UV16_PACKED 0x09 |
nkeynes@189 | 56 | #define TA_VERTEX_TEX_UV16_SPEC_PACKED 0x0D |
nkeynes@189 | 57 | #define TA_VERTEX_FLOAT 0x10 |
nkeynes@189 | 58 | #define TA_VERTEX_TEX_FLOAT 0x18 |
nkeynes@189 | 59 | #define TA_VERTEX_TEX_SPEC_FLOAT 0x1C |
nkeynes@189 | 60 | #define TA_VERTEX_TEX_UV16_FLOAT 0x19 |
nkeynes@189 | 61 | #define TA_VERTEX_TEX_UV16_SPEC_FLOAT 0x1D |
nkeynes@189 | 62 | #define TA_VERTEX_INTENSITY 0x20 |
nkeynes@189 | 63 | #define TA_VERTEX_TEX_INTENSITY 0x28 |
nkeynes@189 | 64 | #define TA_VERTEX_TEX_SPEC_INTENSITY 0x2C |
nkeynes@189 | 65 | #define TA_VERTEX_TEX_UV16_INTENSITY 0x29 |
nkeynes@189 | 66 | #define TA_VERTEX_TEX_UV16_SPEC_INTENSITY 0x2D |
nkeynes@189 | 67 | #define TA_VERTEX_PACKED_MOD 0x40 |
nkeynes@189 | 68 | #define TA_VERTEX_TEX_PACKED_MOD 0x48 |
nkeynes@189 | 69 | #define TA_VERTEX_TEX_SPEC_PACKED_MOD 0x4C |
nkeynes@189 | 70 | #define TA_VERTEX_TEX_UV16_PACKED_MOD 0x49 |
nkeynes@189 | 71 | #define TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD 0x4D |
nkeynes@189 | 72 | #define TA_VERTEX_INTENSITY_MOD 0x60 |
nkeynes@189 | 73 | #define TA_VERTEX_TEX_INTENSITY_MOD 0x68 |
nkeynes@189 | 74 | #define TA_VERTEX_TEX_SPEC_INTENSITY_MOD 0x6C |
nkeynes@189 | 75 | #define TA_VERTEX_TEX_UV16_INTENSITY_MOD 0x69 |
nkeynes@189 | 76 | #define TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD 0x6D |
nkeynes@189 | 77 | #define TA_VERTEX_SPRITE 0x80 |
nkeynes@189 | 78 | #define TA_VERTEX_TEX_SPRITE 0x88 |
nkeynes@189 | 79 | #define TA_VERTEX_MOD_VOLUME 0x81 |
nkeynes@206 | 80 | #define TA_VERTEX_LISTLESS 0xFF |
nkeynes@189 | 81 | |
nkeynes@189 | 82 | #define TA_IS_NORMAL_POLY() (ta_status.current_vertex_type < TA_VERTEX_SPRITE) |
nkeynes@189 | 83 | |
nkeynes@189 | 84 | static int strip_lengths[4] = {3,4,6,8}; /* in vertexes */ |
nkeynes@189 | 85 | #define TA_POLYCMD_LISTTYPE(i) ( ((i) >> 24) & 0x0F ) |
nkeynes@194 | 86 | #define TA_POLYCMD_USELENGTH(i) ( i & 0x00800000 ) |
nkeynes@189 | 87 | #define TA_POLYCMD_LENGTH(i) strip_lengths[((i >> 18) & 0x03)] |
nkeynes@189 | 88 | #define TA_POLYCMD_CLIP(i) ((i>>16)&0x03) |
nkeynes@203 | 89 | #define TA_POLYCMD_CLIP_NONE 0 |
nkeynes@203 | 90 | #define TA_POLYCMD_CLIP_INSIDE 2 |
nkeynes@203 | 91 | #define TA_POLYCMD_CLIP_OUTSIDE 3 |
nkeynes@189 | 92 | #define TA_POLYCMD_COLOURFMT(i) (i & 0x00000030) |
nkeynes@189 | 93 | #define TA_POLYCMD_COLOURFMT_ARGB32 0x00000000 |
nkeynes@189 | 94 | #define TA_POLYCMD_COLOURFMT_FLOAT 0x00000010 |
nkeynes@189 | 95 | #define TA_POLYCMD_COLOURFMT_INTENSITY 0x00000020 |
nkeynes@189 | 96 | #define TA_POLYCMD_COLOURFMT_LASTINT 0x00000030 |
nkeynes@189 | 97 | |
nkeynes@189 | 98 | #define TA_POLYCMD_MODIFIED 0x00000080 |
nkeynes@189 | 99 | #define TA_POLYCMD_FULLMOD 0x00000040 |
nkeynes@189 | 100 | #define TA_POLYCMD_TEXTURED 0x00000008 |
nkeynes@189 | 101 | #define TA_POLYCMD_SPECULAR 0x00000004 |
nkeynes@189 | 102 | #define TA_POLYCMD_SHADED 0x00000002 |
nkeynes@189 | 103 | #define TA_POLYCMD_UV16 0x00000001 |
nkeynes@189 | 104 | |
nkeynes@189 | 105 | #define TA_POLYCMD_IS_SPECULAR(i) ((i & 0x0000000C)==0x0000000C) /* Only applies to textured polys */ |
nkeynes@189 | 106 | #define TA_POLYCMD_IS_FULLMOD(i) ((i & 0x000000C0)==0x000000C0) |
nkeynes@189 | 107 | |
nkeynes@189 | 108 | |
nkeynes@189 | 109 | #define TA_IS_END_VERTEX(i) (i & 0x10000000) |
nkeynes@189 | 110 | |
nkeynes@199 | 111 | /** Note these are not the IEEE 754 definitions - the TA treats NANs |
nkeynes@199 | 112 | * as if they were INFs of the appropriate sign. |
nkeynes@199 | 113 | */ |
nkeynes@199 | 114 | #define TA_IS_INF(f) (((*((uint32_t *)&f)) & 0xFF800000) == 0x7F800000) |
nkeynes@199 | 115 | #define TA_IS_NINF(f) (((*((uint32_t *)&f)) & 0xFF800000) == 0xFF800000) |
nkeynes@199 | 116 | |
nkeynes@189 | 117 | #define MIN3( x1, x2, x3 ) ( (x1)<(x2)? ((x1)<(x3)?(x1):(x3)) : ((x2)<(x3)?(x2):(x3)) ) |
nkeynes@189 | 118 | #define MAX3( x1, x2, x3 ) ( (x1)>(x2)? ((x1)>(x3)?(x1):(x3)) : ((x2)>(x3)?(x2):(x3)) ) |
nkeynes@189 | 119 | |
nkeynes@189 | 120 | #define TILESLOT( x, y ) (ta_status.current_tile_matrix + (ta_status.current_tile_size * (y * ta_status.width+ x) << 2)) |
nkeynes@189 | 121 | |
nkeynes@953 | 122 | #define PVRRAM(addr) (*(uint32_t *)(pvr2_main_ram + ((addr)&PVR2_RAM_MASK))) |
nkeynes@189 | 123 | |
nkeynes@189 | 124 | struct pvr2_ta_vertex { |
nkeynes@189 | 125 | float x,y,z; |
nkeynes@189 | 126 | uint32_t detail[8]; /* 0-8 detail words */ |
nkeynes@189 | 127 | }; |
nkeynes@189 | 128 | |
nkeynes@189 | 129 | struct tile_bounds { |
nkeynes@674 | 130 | int32_t x1, y1, x2, y2; |
nkeynes@189 | 131 | }; |
nkeynes@189 | 132 | |
nkeynes@189 | 133 | struct pvr2_ta_status { |
nkeynes@674 | 134 | int32_t state; |
nkeynes@674 | 135 | int32_t width, height; /* Tile resolution, ie 20x15 */ |
nkeynes@674 | 136 | int32_t tilelist_dir; /* Growth direction of the tilelist, 0 = up, 1 = down */ |
nkeynes@189 | 137 | uint32_t tilelist_size; /* Size of the tilelist segments */ |
nkeynes@193 | 138 | uint32_t tilelist_start; /* Initial address of the tilelist */ |
nkeynes@674 | 139 | uint32_t polybuf_start; /* Initial bank address of the polygon buffer (ie &0x00F00000) */ |
nkeynes@674 | 140 | int32_t current_vertex_type; |
nkeynes@674 | 141 | uint32_t accept_vertexes; /* 0 = NO, 1 = YES */ |
nkeynes@674 | 142 | int32_t vertex_count; /* index of last start-vertex seen, or -1 if no vertexes |
nkeynes@736 | 143 | * are present |
nkeynes@736 | 144 | */ |
nkeynes@674 | 145 | uint32_t max_vertex; /* Maximum number of vertexes in the current polygon (3/4/6/8) */ |
nkeynes@674 | 146 | uint32_t current_list_type; |
nkeynes@189 | 147 | uint32_t current_tile_matrix; /* Memory location of the first tile for the current list. */ |
nkeynes@189 | 148 | uint32_t current_tile_size; /* Size of the tile matrix space in 32-bit words (0/8/16/32)*/ |
nkeynes@189 | 149 | uint32_t intensity1, intensity2; |
nkeynes@203 | 150 | struct tile_bounds clip; |
nkeynes@674 | 151 | int32_t clip_mode; |
nkeynes@189 | 152 | /** |
nkeynes@189 | 153 | * Current working object |
nkeynes@189 | 154 | */ |
nkeynes@674 | 155 | int32_t poly_context_size; |
nkeynes@674 | 156 | int32_t poly_vertex_size; |
nkeynes@674 | 157 | int32_t poly_parity; |
nkeynes@189 | 158 | uint32_t poly_context[5]; |
nkeynes@189 | 159 | uint32_t poly_pointer; |
nkeynes@189 | 160 | struct tile_bounds last_triangle_bounds; |
nkeynes@189 | 161 | struct pvr2_ta_vertex poly_vertex[8]; |
nkeynes@674 | 162 | uint32_t debug_output; |
nkeynes@189 | 163 | }; |
nkeynes@189 | 164 | |
nkeynes@189 | 165 | static struct pvr2_ta_status ta_status; |
nkeynes@189 | 166 | |
nkeynes@189 | 167 | static int tilematrix_sizes[4] = {0,8,16,32}; |
nkeynes@189 | 168 | |
nkeynes@189 | 169 | /** |
nkeynes@189 | 170 | * Convenience union - ta data is either 32-bit integer or 32-bit float. |
nkeynes@189 | 171 | */ |
nkeynes@189 | 172 | union ta_data { |
nkeynes@189 | 173 | unsigned int i; |
nkeynes@189 | 174 | float f; |
nkeynes@189 | 175 | }; |
nkeynes@189 | 176 | |
nkeynes@189 | 177 | |
nkeynes@189 | 178 | void pvr2_ta_reset() { |
nkeynes@189 | 179 | ta_status.state = STATE_ERROR; /* State not valid until initialized */ |
nkeynes@189 | 180 | ta_status.debug_output = 0; |
nkeynes@189 | 181 | } |
nkeynes@189 | 182 | |
nkeynes@193 | 183 | void pvr2_ta_save_state( FILE *f ) |
nkeynes@193 | 184 | { |
nkeynes@193 | 185 | fwrite( &ta_status, sizeof(ta_status), 1, f ); |
nkeynes@193 | 186 | } |
nkeynes@193 | 187 | |
nkeynes@193 | 188 | int pvr2_ta_load_state( FILE *f ) |
nkeynes@193 | 189 | { |
nkeynes@193 | 190 | if( fread( &ta_status, sizeof(ta_status), 1, f ) != 1 ) |
nkeynes@736 | 191 | return 1; |
nkeynes@193 | 192 | return 0; |
nkeynes@193 | 193 | } |
nkeynes@193 | 194 | |
nkeynes@189 | 195 | void pvr2_ta_init() { |
nkeynes@189 | 196 | ta_status.state = STATE_IDLE; |
nkeynes@189 | 197 | ta_status.current_list_type = -1; |
nkeynes@189 | 198 | ta_status.current_vertex_type = -1; |
nkeynes@189 | 199 | ta_status.poly_parity = 0; |
nkeynes@189 | 200 | ta_status.vertex_count = 0; |
nkeynes@189 | 201 | ta_status.max_vertex = 3; |
nkeynes@206 | 202 | ta_status.current_vertex_type = TA_VERTEX_LISTLESS; |
nkeynes@206 | 203 | ta_status.poly_vertex_size = 0; |
nkeynes@206 | 204 | memset(&ta_status.poly_context[1], 0, 4); |
nkeynes@189 | 205 | ta_status.last_triangle_bounds.x1 = -1; |
nkeynes@193 | 206 | ta_status.accept_vertexes = TRUE; |
nkeynes@198 | 207 | ta_status.clip.x1 = 0; |
nkeynes@198 | 208 | ta_status.clip.y1 = 0; |
nkeynes@203 | 209 | ta_status.clip_mode = TA_POLYCMD_CLIP_NONE; |
nkeynes@198 | 210 | |
nkeynes@189 | 211 | uint32_t size = MMIO_READ( PVR2, TA_TILESIZE ); |
nkeynes@189 | 212 | ta_status.width = (size & 0xFFFF) + 1; |
nkeynes@189 | 213 | ta_status.height = (size >> 16) + 1; |
nkeynes@198 | 214 | ta_status.clip.x2 = ta_status.width-1; |
nkeynes@198 | 215 | ta_status.clip.y2 = ta_status.height-1; |
nkeynes@189 | 216 | uint32_t control = MMIO_READ( PVR2, TA_TILECFG ); |
nkeynes@189 | 217 | ta_status.tilelist_dir = (control >> 20) & 0x01; |
nkeynes@189 | 218 | ta_status.tilelist_size = tilematrix_sizes[ (control & 0x03) ]; |
nkeynes@189 | 219 | MMIO_WRITE( PVR2, TA_POLYPOS, MMIO_READ( PVR2, TA_POLYBASE ) ); |
nkeynes@189 | 220 | uint32_t plistpos = MMIO_READ( PVR2, TA_LISTBASE ) >> 2; |
nkeynes@189 | 221 | if( ta_status.tilelist_dir == TA_GROW_DOWN ) { |
nkeynes@736 | 222 | plistpos -= ta_status.tilelist_size; |
nkeynes@189 | 223 | } |
nkeynes@189 | 224 | MMIO_WRITE( PVR2, TA_LISTPOS, plistpos ); |
nkeynes@193 | 225 | ta_status.tilelist_start = plistpos; |
nkeynes@215 | 226 | ta_status.polybuf_start = MMIO_READ( PVR2, TA_POLYBASE ) & 0x00F00000; |
nkeynes@189 | 227 | } |
nkeynes@189 | 228 | |
nkeynes@189 | 229 | static uint32_t parse_float_colour( float a, float r, float g, float b ) { |
nkeynes@200 | 230 | int ai,ri,gi,bi; |
nkeynes@200 | 231 | |
nkeynes@200 | 232 | if( TA_IS_INF(a) ) { |
nkeynes@736 | 233 | ai = 255; |
nkeynes@200 | 234 | } else { |
nkeynes@736 | 235 | ai = 256 * CLAMP(a,0.0,1.0) - 1; |
nkeynes@736 | 236 | if( ai < 0 ) ai = 0; |
nkeynes@200 | 237 | } |
nkeynes@200 | 238 | if( TA_IS_INF(r) ) { |
nkeynes@736 | 239 | ri = 255; |
nkeynes@200 | 240 | } else { |
nkeynes@736 | 241 | ri = 256 * CLAMP(r,0.0,1.0) - 1; |
nkeynes@736 | 242 | if( ri < 0 ) ri = 0; |
nkeynes@200 | 243 | } |
nkeynes@200 | 244 | if( TA_IS_INF(g) ) { |
nkeynes@736 | 245 | gi = 255; |
nkeynes@200 | 246 | } else { |
nkeynes@736 | 247 | gi = 256 * CLAMP(g,0.0,1.0) - 1; |
nkeynes@736 | 248 | if( gi < 0 ) gi = 0; |
nkeynes@200 | 249 | } |
nkeynes@200 | 250 | if( TA_IS_INF(b) ) { |
nkeynes@736 | 251 | bi = 255; |
nkeynes@200 | 252 | } else { |
nkeynes@736 | 253 | bi = 256 * CLAMP(b,0.0,1.0) - 1; |
nkeynes@736 | 254 | if( bi < 0 ) bi = 0; |
nkeynes@200 | 255 | } |
nkeynes@200 | 256 | return (ai << 24) | (ri << 16) | (gi << 8) | bi; |
nkeynes@189 | 257 | } |
nkeynes@189 | 258 | |
nkeynes@189 | 259 | static uint32_t parse_intensity_colour( uint32_t base, float intensity ) |
nkeynes@189 | 260 | { |
nkeynes@189 | 261 | unsigned int i = (unsigned int)(256 * CLAMP(intensity, 0.0,1.0)); |
nkeynes@736 | 262 | |
nkeynes@189 | 263 | return |
nkeynes@736 | 264 | (((((base & 0xFF) * i) & 0xFF00) | |
nkeynes@736 | 265 | (((base & 0xFF00) * i) & 0xFF0000) | |
nkeynes@736 | 266 | (((base & 0xFF0000) * i) & 0xFF000000)) >> 8) | |
nkeynes@736 | 267 | (base & 0xFF000000); |
nkeynes@189 | 268 | } |
nkeynes@736 | 269 | |
nkeynes@189 | 270 | /** |
nkeynes@189 | 271 | * Initialize the specified TA list. |
nkeynes@189 | 272 | */ |
nkeynes@189 | 273 | static void ta_init_list( unsigned int listtype ) { |
nkeynes@189 | 274 | int config = MMIO_READ( PVR2, TA_TILECFG ); |
nkeynes@189 | 275 | int tile_matrix = MMIO_READ( PVR2, TA_TILEBASE ); |
nkeynes@193 | 276 | int list_end = MMIO_READ( PVR2, TA_LISTEND ); |
nkeynes@193 | 277 | |
nkeynes@193 | 278 | ta_status.current_tile_matrix = tile_matrix; |
nkeynes@193 | 279 | |
nkeynes@193 | 280 | /* If the list grows down, the end must be < tile matrix start. |
nkeynes@193 | 281 | * If it grows up, the end must be > tile matrix start. |
nkeynes@193 | 282 | * Don't ask me why, it just does... |
nkeynes@193 | 283 | */ |
nkeynes@193 | 284 | if( ((ta_status.tilelist_dir == TA_GROW_DOWN && list_end <= tile_matrix) || |
nkeynes@736 | 285 | (ta_status.tilelist_dir == TA_GROW_UP && list_end >= tile_matrix )) && |
nkeynes@736 | 286 | listtype <= TA_LIST_PUNCH_OUT ) { |
nkeynes@736 | 287 | int i; |
nkeynes@736 | 288 | uint32_t *p; |
nkeynes@736 | 289 | for( i=0; i < listtype; i++ ) { |
nkeynes@736 | 290 | int size = tilematrix_sizes[(config & 0x03)] << 2; |
nkeynes@736 | 291 | ta_status.current_tile_matrix += ta_status.width * ta_status.height * size; |
nkeynes@736 | 292 | config >>= 4; |
nkeynes@736 | 293 | } |
nkeynes@736 | 294 | ta_status.current_tile_size = tilematrix_sizes[(config & 0x03)]; |
nkeynes@189 | 295 | |
nkeynes@736 | 296 | /* Initialize each tile to 0xF0000000 */ |
nkeynes@736 | 297 | if( ta_status.current_tile_size != 0 ) { |
nkeynes@953 | 298 | p = (uint32_t *)(pvr2_main_ram + ta_status.current_tile_matrix); |
nkeynes@736 | 299 | for( i=0; i< ta_status.width * ta_status.height; i++ ) { |
nkeynes@736 | 300 | *p = 0xF0000000; |
nkeynes@736 | 301 | p += ta_status.current_tile_size; |
nkeynes@736 | 302 | } |
nkeynes@736 | 303 | } |
nkeynes@193 | 304 | } else { |
nkeynes@736 | 305 | ta_status.current_tile_size = 0; |
nkeynes@189 | 306 | } |
nkeynes@193 | 307 | |
nkeynes@193 | 308 | if( tile_matrix == list_end ) { |
nkeynes@736 | 309 | ta_status.current_tile_size = 0; |
nkeynes@193 | 310 | } |
nkeynes@193 | 311 | |
nkeynes@189 | 312 | ta_status.state = STATE_IN_LIST; |
nkeynes@189 | 313 | ta_status.current_list_type = listtype; |
nkeynes@189 | 314 | ta_status.last_triangle_bounds.x1 = -1; |
nkeynes@189 | 315 | } |
nkeynes@189 | 316 | |
nkeynes@189 | 317 | static int list_events[5] = {EVENT_PVR_OPAQUE_DONE, EVENT_PVR_OPAQUEMOD_DONE, |
nkeynes@736 | 318 | EVENT_PVR_TRANS_DONE, EVENT_PVR_TRANSMOD_DONE, |
nkeynes@736 | 319 | EVENT_PVR_PUNCHOUT_DONE }; |
nkeynes@189 | 320 | |
nkeynes@189 | 321 | static void ta_end_list() { |
nkeynes@189 | 322 | if( ta_status.current_list_type != TA_LIST_NONE ) { |
nkeynes@736 | 323 | asic_event( list_events[ta_status.current_list_type] ); |
nkeynes@189 | 324 | } |
nkeynes@206 | 325 | ta_status.current_list_type = TA_LIST_NONE; |
nkeynes@206 | 326 | ta_status.current_vertex_type = TA_VERTEX_LISTLESS; |
nkeynes@206 | 327 | ta_status.poly_vertex_size = 0; |
nkeynes@206 | 328 | memset(&ta_status.poly_context[1], 0, 4); |
nkeynes@206 | 329 | ta_status.state = STATE_IDLE; |
nkeynes@206 | 330 | } |
nkeynes@206 | 331 | |
nkeynes@206 | 332 | static void ta_bad_input_error() { |
nkeynes@206 | 333 | asic_event( EVENT_PVR_BAD_INPUT ); |
nkeynes@189 | 334 | } |
nkeynes@189 | 335 | |
nkeynes@189 | 336 | /** |
nkeynes@189 | 337 | * Write data out to the polygon buffer. |
nkeynes@189 | 338 | * If the end-of-buffer is reached, asserts EVENT_PVR_PRIM_ALLOC_FAIL |
nkeynes@189 | 339 | * @param data to be written |
nkeynes@189 | 340 | * @param length Number of 32-bit words to write. |
nkeynes@189 | 341 | * @return number of words actually written |
nkeynes@189 | 342 | */ |
nkeynes@189 | 343 | static int ta_write_polygon_buffer( uint32_t *data, int length ) |
nkeynes@189 | 344 | { |
nkeynes@189 | 345 | int rv; |
nkeynes@189 | 346 | int posn = MMIO_READ( PVR2, TA_POLYPOS ); |
nkeynes@189 | 347 | int end = MMIO_READ( PVR2, TA_POLYEND ); |
nkeynes@953 | 348 | uint32_t *target = (uint32_t *)(pvr2_main_ram + posn); |
nkeynes@189 | 349 | for( rv=0; rv < length; rv++ ) { |
nkeynes@736 | 350 | if( posn == end ) { |
nkeynes@736 | 351 | asic_event( EVENT_PVR_PRIM_ALLOC_FAIL ); |
nkeynes@736 | 352 | // ta_status.state = STATE_ERROR; |
nkeynes@736 | 353 | break; |
nkeynes@736 | 354 | } |
nkeynes@736 | 355 | if( posn < PVR2_RAM_SIZE ) { |
nkeynes@736 | 356 | *target++ = *data++; |
nkeynes@736 | 357 | } |
nkeynes@736 | 358 | posn += 4; |
nkeynes@189 | 359 | } |
nkeynes@189 | 360 | |
nkeynes@189 | 361 | MMIO_WRITE( PVR2, TA_POLYPOS, posn ); |
nkeynes@189 | 362 | return rv; |
nkeynes@189 | 363 | } |
nkeynes@189 | 364 | |
nkeynes@193 | 365 | #define TA_NO_ALLOC 0xFFFFFFFF |
nkeynes@193 | 366 | |
nkeynes@189 | 367 | /** |
nkeynes@193 | 368 | * Allocate a new tile list block from the grow space and update the |
nkeynes@193 | 369 | * word at reference to be a link to the new block. |
nkeynes@189 | 370 | */ |
nkeynes@193 | 371 | static uint32_t ta_alloc_tilelist( uint32_t reference ) { |
nkeynes@189 | 372 | uint32_t posn = MMIO_READ( PVR2, TA_LISTPOS ); |
nkeynes@193 | 373 | uint32_t limit = MMIO_READ( PVR2, TA_LISTEND ) >> 2; |
nkeynes@189 | 374 | uint32_t newposn; |
nkeynes@189 | 375 | if( ta_status.tilelist_dir == TA_GROW_DOWN ) { |
nkeynes@736 | 376 | newposn = posn - ta_status.tilelist_size; |
nkeynes@736 | 377 | if( posn == limit ) { |
nkeynes@736 | 378 | PVRRAM(posn<<2) = 0xF0000000; |
nkeynes@736 | 379 | PVRRAM(reference) = 0xE0000000 | (posn<<2); |
nkeynes@736 | 380 | return TA_NO_ALLOC; |
nkeynes@736 | 381 | } else if( posn < limit ) { |
nkeynes@736 | 382 | PVRRAM(reference) = 0xE0000000 | (posn<<2); |
nkeynes@736 | 383 | return TA_NO_ALLOC; |
nkeynes@736 | 384 | } else if( newposn <= limit ) { |
nkeynes@736 | 385 | } else if( newposn <= (limit + ta_status.tilelist_size) ) { |
nkeynes@736 | 386 | asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL ); |
nkeynes@736 | 387 | MMIO_WRITE( PVR2, TA_LISTPOS, newposn ); |
nkeynes@736 | 388 | } else { |
nkeynes@736 | 389 | MMIO_WRITE( PVR2, TA_LISTPOS, newposn ); |
nkeynes@736 | 390 | } |
nkeynes@736 | 391 | PVRRAM(reference) = 0xE0000000 | (posn<<2); |
nkeynes@736 | 392 | return posn << 2; |
nkeynes@189 | 393 | } else { |
nkeynes@736 | 394 | newposn = posn + ta_status.tilelist_size; |
nkeynes@736 | 395 | if( posn == limit ) { |
nkeynes@736 | 396 | PVRRAM(posn<<2) = 0xF0000000; |
nkeynes@736 | 397 | PVRRAM(reference) = 0xE0000000 | (posn<<2); |
nkeynes@736 | 398 | return TA_NO_ALLOC; |
nkeynes@736 | 399 | } else if ( posn > limit ) { |
nkeynes@736 | 400 | PVRRAM(reference) = 0xE0000000 | (posn<<2); |
nkeynes@736 | 401 | return TA_NO_ALLOC; |
nkeynes@736 | 402 | } else if( newposn >= limit ) { |
nkeynes@736 | 403 | } else if( newposn >= (limit - ta_status.tilelist_size) ) { |
nkeynes@736 | 404 | asic_event( EVENT_PVR_MATRIX_ALLOC_FAIL ); |
nkeynes@736 | 405 | MMIO_WRITE( PVR2, TA_LISTPOS, newposn ); |
nkeynes@736 | 406 | } else { |
nkeynes@736 | 407 | MMIO_WRITE( PVR2, TA_LISTPOS, newposn ); |
nkeynes@736 | 408 | } |
nkeynes@736 | 409 | PVRRAM(reference) = 0xE0000000 | (posn<<2); |
nkeynes@736 | 410 | return posn << 2; |
nkeynes@189 | 411 | } |
nkeynes@189 | 412 | } |
nkeynes@189 | 413 | |
nkeynes@189 | 414 | /** |
nkeynes@189 | 415 | * Write a tile entry out to the matrix. |
nkeynes@189 | 416 | */ |
nkeynes@429 | 417 | static void ta_write_tile_entry( int x, int y, uint32_t tile_entry ) { |
nkeynes@189 | 418 | uint32_t tile = TILESLOT(x,y); |
nkeynes@193 | 419 | uint32_t tilestart = tile; |
nkeynes@189 | 420 | uint32_t value; |
nkeynes@189 | 421 | uint32_t lasttri = 0; |
nkeynes@429 | 422 | int i; |
nkeynes@189 | 423 | |
nkeynes@203 | 424 | if( ta_status.clip_mode == TA_POLYCMD_CLIP_OUTSIDE && |
nkeynes@736 | 425 | x >= ta_status.clip.x1 && x <= ta_status.clip.x2 && |
nkeynes@736 | 426 | y >= ta_status.clip.y1 && y <= ta_status.clip.y2 ) { |
nkeynes@736 | 427 | /* Tile clipped out */ |
nkeynes@736 | 428 | return; |
nkeynes@203 | 429 | } |
nkeynes@203 | 430 | |
nkeynes@189 | 431 | if( (tile_entry & 0x80000000) && |
nkeynes@736 | 432 | ta_status.last_triangle_bounds.x1 != -1 && |
nkeynes@736 | 433 | ta_status.last_triangle_bounds.x1 <= x && |
nkeynes@736 | 434 | ta_status.last_triangle_bounds.x2 >= x && |
nkeynes@736 | 435 | ta_status.last_triangle_bounds.y1 <= y && |
nkeynes@736 | 436 | ta_status.last_triangle_bounds.y2 >= y ) { |
nkeynes@736 | 437 | /* potential for triangle stacking */ |
nkeynes@736 | 438 | lasttri = tile_entry & 0xE1E00000; |
nkeynes@189 | 439 | } |
nkeynes@736 | 440 | |
nkeynes@736 | 441 | |
nkeynes@189 | 442 | if( PVRRAM(tile) == 0xF0000000 ) { |
nkeynes@736 | 443 | PVRRAM(tile) = tile_entry; |
nkeynes@736 | 444 | PVRRAM(tile+4) = 0xF0000000; |
nkeynes@736 | 445 | return; |
nkeynes@189 | 446 | } |
nkeynes@189 | 447 | |
nkeynes@189 | 448 | while(1) { |
nkeynes@736 | 449 | value = PVRRAM(tile); |
nkeynes@736 | 450 | for( i=1; i<ta_status.current_tile_size; i++ ) { |
nkeynes@736 | 451 | tile += 4; |
nkeynes@736 | 452 | uint32_t nextval = PVRRAM(tile); |
nkeynes@736 | 453 | if( nextval == 0xF0000000 ) { |
nkeynes@736 | 454 | if( lasttri != 0 && lasttri == (value&0xE1E00000) ) { |
nkeynes@736 | 455 | int count = (value & 0x1E000000) + 0x02000000; |
nkeynes@736 | 456 | if( count < 0x20000000 ) { |
nkeynes@736 | 457 | PVRRAM(tile-4) = (value & 0xE1FFFFFF) | count; |
nkeynes@736 | 458 | return; |
nkeynes@736 | 459 | } |
nkeynes@736 | 460 | } |
nkeynes@736 | 461 | if( i < ta_status.current_tile_size-1 ) { |
nkeynes@736 | 462 | PVRRAM(tile) = tile_entry; |
nkeynes@736 | 463 | PVRRAM(tile+4) = 0xF0000000; |
nkeynes@736 | 464 | return; |
nkeynes@736 | 465 | } |
nkeynes@736 | 466 | } |
nkeynes@736 | 467 | value = nextval; |
nkeynes@736 | 468 | } |
nkeynes@189 | 469 | |
nkeynes@736 | 470 | if( value == 0xF0000000 ) { |
nkeynes@736 | 471 | tile = ta_alloc_tilelist(tile); |
nkeynes@736 | 472 | if( tile != TA_NO_ALLOC ) { |
nkeynes@736 | 473 | PVRRAM(tile) = tile_entry; |
nkeynes@736 | 474 | PVRRAM(tile+4) = 0xF0000000; |
nkeynes@736 | 475 | } |
nkeynes@736 | 476 | return; |
nkeynes@736 | 477 | } else if( (value & 0xFF000000) == 0xE0000000 ) { |
nkeynes@736 | 478 | value &= 0x00FFFFFF; |
nkeynes@736 | 479 | if( value == tilestart ) |
nkeynes@736 | 480 | return; /* Loop */ |
nkeynes@736 | 481 | tilestart = tile = value; |
nkeynes@736 | 482 | } else { |
nkeynes@736 | 483 | /* This should never happen */ |
nkeynes@736 | 484 | return; |
nkeynes@736 | 485 | } |
nkeynes@189 | 486 | } |
nkeynes@189 | 487 | } |
nkeynes@189 | 488 | |
nkeynes@189 | 489 | /** |
nkeynes@189 | 490 | * Write a completed polygon out to the memory buffers |
nkeynes@189 | 491 | * OPTIMIZEME: This is not terribly efficient at the moment. |
nkeynes@189 | 492 | */ |
nkeynes@189 | 493 | static void ta_commit_polygon( ) { |
nkeynes@189 | 494 | int i, x, y; |
nkeynes@189 | 495 | int tx[ta_status.vertex_count], ty[ta_status.vertex_count]; |
nkeynes@189 | 496 | struct tile_bounds triangle_bound[ta_status.vertex_count - 2]; |
nkeynes@189 | 497 | struct tile_bounds polygon_bound; |
nkeynes@189 | 498 | uint32_t poly_context[5]; |
nkeynes@189 | 499 | |
nkeynes@189 | 500 | memcpy( poly_context, ta_status.poly_context, ta_status.poly_context_size * 4 ); |
nkeynes@189 | 501 | |
nkeynes@189 | 502 | /* Compute the tile coordinates for each vertex (need to be careful with |
nkeynes@189 | 503 | * clamping here) |
nkeynes@189 | 504 | */ |
nkeynes@189 | 505 | for( i=0; i<ta_status.vertex_count; i++ ) { |
nkeynes@736 | 506 | if( ta_status.poly_vertex[i].x < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].x) ) { |
nkeynes@736 | 507 | tx[i] = -1; |
nkeynes@736 | 508 | } else if( ta_status.poly_vertex[i].x > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].x) ) { |
nkeynes@736 | 509 | tx[i] = INT_MAX/32; |
nkeynes@736 | 510 | } else { |
nkeynes@736 | 511 | tx[i] = (int)(ta_status.poly_vertex[i].x / 32.0); |
nkeynes@736 | 512 | } |
nkeynes@736 | 513 | if( ta_status.poly_vertex[i].y < 0.0 || TA_IS_NINF(ta_status.poly_vertex[i].y)) { |
nkeynes@736 | 514 | ty[i] = -1; |
nkeynes@736 | 515 | } else if( ta_status.poly_vertex[i].y > (float)INT_MAX || TA_IS_INF(ta_status.poly_vertex[i].y) ) { |
nkeynes@736 | 516 | ty[i] = INT_MAX/32; |
nkeynes@736 | 517 | } else { |
nkeynes@736 | 518 | ty[i] = (int)(ta_status.poly_vertex[i].y / 32.0); |
nkeynes@736 | 519 | } |
nkeynes@736 | 520 | |
nkeynes@189 | 521 | } |
nkeynes@189 | 522 | |
nkeynes@189 | 523 | /* Compute bounding box for each triangle individually, as well |
nkeynes@189 | 524 | * as the overall polygon. |
nkeynes@189 | 525 | */ |
nkeynes@189 | 526 | |
nkeynes@801 | 527 | triangle_bound[0].x1 = MIN3(tx[0],tx[1],tx[2]); |
nkeynes@801 | 528 | triangle_bound[0].x2 = MAX3(tx[0],tx[1],tx[2]); |
nkeynes@801 | 529 | triangle_bound[0].y1 = MIN3(ty[0],ty[1],ty[2]); |
nkeynes@801 | 530 | triangle_bound[0].y2 = MAX3(ty[0],ty[1],ty[2]); |
nkeynes@801 | 531 | polygon_bound.x1 = triangle_bound[0].x1; |
nkeynes@801 | 532 | polygon_bound.y1 = triangle_bound[0].y1; |
nkeynes@801 | 533 | polygon_bound.x2 = triangle_bound[0].x2; |
nkeynes@801 | 534 | polygon_bound.y2 = triangle_bound[0].y2; |
nkeynes@801 | 535 | |
nkeynes@801 | 536 | for( i=1; i<ta_status.vertex_count-2; i++ ) { |
nkeynes@736 | 537 | triangle_bound[i].x1 = MIN3(tx[i],tx[i+1],tx[i+2]); |
nkeynes@736 | 538 | triangle_bound[i].x2 = MAX3(tx[i],tx[i+1],tx[i+2]); |
nkeynes@736 | 539 | triangle_bound[i].y1 = MIN3(ty[i],ty[i+1],ty[i+2]); |
nkeynes@736 | 540 | triangle_bound[i].y2 = MAX3(ty[i],ty[i+1],ty[i+2]); |
nkeynes@801 | 541 | polygon_bound.x1 = MIN(polygon_bound.x1, triangle_bound[i].x1); |
nkeynes@801 | 542 | polygon_bound.x2 = MAX(polygon_bound.x2, triangle_bound[i].x2); |
nkeynes@801 | 543 | polygon_bound.y1 = MIN(polygon_bound.y1, triangle_bound[i].y1); |
nkeynes@801 | 544 | polygon_bound.y2 = MAX(polygon_bound.y2, triangle_bound[i].y2); |
nkeynes@189 | 545 | } |
nkeynes@189 | 546 | |
nkeynes@189 | 547 | /* Clamp the polygon bounds to the frustum */ |
nkeynes@189 | 548 | if( polygon_bound.x1 < 0 ) polygon_bound.x1 = 0; |
nkeynes@189 | 549 | if( polygon_bound.x2 >= ta_status.width ) polygon_bound.x2 = ta_status.width-1; |
nkeynes@189 | 550 | if( polygon_bound.y1 < 0 ) polygon_bound.y1 = 0; |
nkeynes@189 | 551 | if( polygon_bound.y2 >= ta_status.width ) polygon_bound.y2 = ta_status.height-1; |
nkeynes@189 | 552 | |
nkeynes@189 | 553 | /* Set the "single tile" flag if it's entirely contained in 1 tile */ |
nkeynes@189 | 554 | if( polygon_bound.x1 == polygon_bound.x2 && |
nkeynes@736 | 555 | polygon_bound.y1 == polygon_bound.y2 ) { |
nkeynes@736 | 556 | poly_context[0] |= 0x00200000; |
nkeynes@189 | 557 | } |
nkeynes@736 | 558 | |
nkeynes@203 | 559 | /* If the polygon is entirely clipped, don't even write the polygon data */ |
nkeynes@203 | 560 | switch( ta_status.clip_mode ) { |
nkeynes@203 | 561 | case TA_POLYCMD_CLIP_NONE: |
nkeynes@736 | 562 | if( polygon_bound.x2 < 0 || polygon_bound.x1 >= ta_status.width || |
nkeynes@736 | 563 | polygon_bound.y2 < 0 || polygon_bound.y1 >= ta_status.height ) { |
nkeynes@736 | 564 | return; |
nkeynes@736 | 565 | } |
nkeynes@736 | 566 | break; |
nkeynes@203 | 567 | case TA_POLYCMD_CLIP_INSIDE: |
nkeynes@736 | 568 | if( polygon_bound.x2 < ta_status.clip.x1 || polygon_bound.x1 > ta_status.clip.x2 || |
nkeynes@736 | 569 | polygon_bound.y2 < ta_status.clip.y1 || polygon_bound.y1 > ta_status.clip.y2 ) { |
nkeynes@736 | 570 | return; |
nkeynes@736 | 571 | } else { |
nkeynes@736 | 572 | /* Clamp to clip bounds */ |
nkeynes@736 | 573 | if( polygon_bound.x1 < ta_status.clip.x1 ) polygon_bound.x1 = ta_status.clip.x1; |
nkeynes@736 | 574 | if( polygon_bound.x2 > ta_status.clip.x2 ) polygon_bound.x2 = ta_status.clip.x2; |
nkeynes@736 | 575 | if( polygon_bound.y1 < ta_status.clip.y1 ) polygon_bound.y1 = ta_status.clip.y1; |
nkeynes@736 | 576 | if( polygon_bound.y2 > ta_status.clip.y2 ) polygon_bound.y2 = ta_status.clip.y2; |
nkeynes@736 | 577 | } |
nkeynes@736 | 578 | break; |
nkeynes@203 | 579 | case TA_POLYCMD_CLIP_OUTSIDE: |
nkeynes@736 | 580 | if( polygon_bound.x1 >= ta_status.clip.x1 && polygon_bound.x2 <= ta_status.clip.x2 && |
nkeynes@736 | 581 | polygon_bound.y1 >= ta_status.clip.y1 && polygon_bound.y2 <= ta_status.clip.y2 ) { |
nkeynes@736 | 582 | return; |
nkeynes@736 | 583 | } |
nkeynes@736 | 584 | break; |
nkeynes@203 | 585 | } |
nkeynes@189 | 586 | |
nkeynes@189 | 587 | /* Ok, we're good to go - write out the polygon first */ |
nkeynes@215 | 588 | uint32_t tile_entry = (MMIO_READ( PVR2, TA_POLYPOS ) - ta_status.polybuf_start) >> 2 | |
nkeynes@736 | 589 | ta_status.poly_pointer; |
nkeynes@736 | 590 | |
nkeynes@189 | 591 | int status = ta_write_polygon_buffer( poly_context, ta_status.poly_context_size ); |
nkeynes@189 | 592 | if( status == 0 ) { |
nkeynes@736 | 593 | /* No memory available - abort */ |
nkeynes@736 | 594 | return; |
nkeynes@189 | 595 | } else { |
nkeynes@736 | 596 | for( i=0; i<ta_status.vertex_count && status != 0; i++ ) { |
nkeynes@736 | 597 | status = ta_write_polygon_buffer( (uint32_t *)(&ta_status.poly_vertex[i]), 3 + ta_status.poly_vertex_size ); |
nkeynes@736 | 598 | } |
nkeynes@189 | 599 | } |
nkeynes@189 | 600 | |
nkeynes@193 | 601 | if( ta_status.current_tile_size == 0 ) { |
nkeynes@736 | 602 | /* No memory for tile entry, so don't write anything */ |
nkeynes@736 | 603 | return; |
nkeynes@193 | 604 | } |
nkeynes@193 | 605 | |
nkeynes@189 | 606 | /* And now the tile entries. Triangles are different from everything else */ |
nkeynes@189 | 607 | if( ta_status.vertex_count == 3 ) { |
nkeynes@736 | 608 | tile_entry |= 0x80000000; |
nkeynes@736 | 609 | for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) { |
nkeynes@736 | 610 | for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) { |
nkeynes@736 | 611 | ta_write_tile_entry( x,y,tile_entry ); |
nkeynes@736 | 612 | } |
nkeynes@736 | 613 | } |
nkeynes@736 | 614 | ta_status.last_triangle_bounds.x1 = polygon_bound.x1; |
nkeynes@736 | 615 | ta_status.last_triangle_bounds.y1 = polygon_bound.y1; |
nkeynes@736 | 616 | ta_status.last_triangle_bounds.x2 = polygon_bound.x2; |
nkeynes@736 | 617 | ta_status.last_triangle_bounds.y2 = polygon_bound.y2; |
nkeynes@189 | 618 | } else if( ta_status.current_vertex_type == TA_VERTEX_SPRITE || |
nkeynes@736 | 619 | ta_status.current_vertex_type == TA_VERTEX_TEX_SPRITE ) { |
nkeynes@736 | 620 | tile_entry |= 0xA0000000; |
nkeynes@736 | 621 | for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) { |
nkeynes@736 | 622 | for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) { |
nkeynes@736 | 623 | ta_write_tile_entry( x,y,tile_entry ); |
nkeynes@736 | 624 | } |
nkeynes@736 | 625 | } |
nkeynes@736 | 626 | ta_status.last_triangle_bounds.x1 = polygon_bound.x1; |
nkeynes@736 | 627 | ta_status.last_triangle_bounds.y1 = polygon_bound.y1; |
nkeynes@736 | 628 | ta_status.last_triangle_bounds.x2 = polygon_bound.x2; |
nkeynes@736 | 629 | ta_status.last_triangle_bounds.y2 = polygon_bound.y2; |
nkeynes@189 | 630 | } else { |
nkeynes@736 | 631 | for( y=polygon_bound.y1; y<=polygon_bound.y2; y++ ) { |
nkeynes@736 | 632 | for( x=polygon_bound.x1; x<=polygon_bound.x2; x++ ) { |
nkeynes@736 | 633 | uint32_t entry = tile_entry; |
nkeynes@736 | 634 | for( i=0; i<ta_status.vertex_count-2; i++ ) { |
nkeynes@736 | 635 | if( triangle_bound[i].x1 <= x && triangle_bound[i].x2 >= x && |
nkeynes@736 | 636 | triangle_bound[i].y1 <= y && triangle_bound[i].y2 >= y ) { |
nkeynes@736 | 637 | entry |= (0x40000000>>i); |
nkeynes@736 | 638 | } |
nkeynes@736 | 639 | } |
nkeynes@736 | 640 | ta_write_tile_entry( x, y, entry ); |
nkeynes@736 | 641 | } |
nkeynes@736 | 642 | } |
nkeynes@736 | 643 | ta_status.last_triangle_bounds.x1 = -1; |
nkeynes@189 | 644 | } |
nkeynes@189 | 645 | } |
nkeynes@189 | 646 | |
nkeynes@189 | 647 | /** |
nkeynes@189 | 648 | * Variant of ta_split_polygon called when vertex_count == max_vertex, but |
nkeynes@189 | 649 | * the client hasn't sent the LAST VERTEX flag. Commit the poly as normal |
nkeynes@189 | 650 | * first, then start a new poly with the first 2 vertexes taken from the |
nkeynes@189 | 651 | * current one. |
nkeynes@189 | 652 | */ |
nkeynes@189 | 653 | static void ta_split_polygon() { |
nkeynes@189 | 654 | ta_commit_polygon(); |
nkeynes@189 | 655 | if( TA_IS_NORMAL_POLY() ) { |
nkeynes@736 | 656 | /* This only applies to ordinary polys - Sprites + modifier lists are |
nkeynes@736 | 657 | * handled differently |
nkeynes@736 | 658 | */ |
nkeynes@736 | 659 | if( ta_status.vertex_count == 3 ) { |
nkeynes@736 | 660 | /* Triangles use an odd/even scheme */ |
nkeynes@736 | 661 | if( ta_status.poly_parity == 0 ) { |
nkeynes@736 | 662 | memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[2], |
nkeynes@736 | 663 | sizeof(struct pvr2_ta_vertex) ); |
nkeynes@736 | 664 | ta_status.poly_parity = 1; |
nkeynes@736 | 665 | } else { |
nkeynes@736 | 666 | memcpy( &ta_status.poly_vertex[1], &ta_status.poly_vertex[2], |
nkeynes@736 | 667 | sizeof(struct pvr2_ta_vertex) ); |
nkeynes@736 | 668 | ta_status.poly_parity = 0; |
nkeynes@736 | 669 | } |
nkeynes@736 | 670 | } else { |
nkeynes@736 | 671 | /* Everything else just uses the last 2 vertexes in order */ |
nkeynes@736 | 672 | memcpy( &ta_status.poly_vertex[0], &ta_status.poly_vertex[ta_status.vertex_count-2], |
nkeynes@736 | 673 | sizeof(struct pvr2_ta_vertex)*2 ); |
nkeynes@736 | 674 | ta_status.poly_parity = 0; |
nkeynes@736 | 675 | } |
nkeynes@736 | 676 | ta_status.vertex_count = 2; |
nkeynes@189 | 677 | } else { |
nkeynes@736 | 678 | ta_status.vertex_count = 0; |
nkeynes@189 | 679 | } |
nkeynes@189 | 680 | } |
nkeynes@189 | 681 | |
nkeynes@189 | 682 | /** |
nkeynes@189 | 683 | * Parse the polygon context block and setup the internal state to receive |
nkeynes@189 | 684 | * vertexes. |
nkeynes@189 | 685 | * @param data 32 bytes of parameter data. |
nkeynes@189 | 686 | */ |
nkeynes@189 | 687 | static void ta_parse_polygon_context( union ta_data *data ) { |
nkeynes@189 | 688 | int colourfmt = TA_POLYCMD_COLOURFMT(data[0].i); |
nkeynes@194 | 689 | if( TA_POLYCMD_USELENGTH(data[0].i) ) { |
nkeynes@736 | 690 | ta_status.max_vertex = TA_POLYCMD_LENGTH(data[0].i); |
nkeynes@194 | 691 | } |
nkeynes@203 | 692 | ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i); |
nkeynes@203 | 693 | if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */ |
nkeynes@736 | 694 | ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE; |
nkeynes@203 | 695 | } |
nkeynes@189 | 696 | ta_status.vertex_count = 0; |
nkeynes@189 | 697 | ta_status.poly_context[0] = |
nkeynes@736 | 698 | (data[1].i & 0xFC1FFFFF) | ((data[0].i & 0x0B) << 22); |
nkeynes@189 | 699 | ta_status.poly_context[1] = data[2].i; |
nkeynes@189 | 700 | ta_status.poly_context[3] = data[4].i; |
nkeynes@189 | 701 | ta_status.poly_parity = 0; |
nkeynes@189 | 702 | if( data[0].i & TA_POLYCMD_TEXTURED ) { |
nkeynes@736 | 703 | ta_status.current_vertex_type = data[0].i & 0x0D; |
nkeynes@736 | 704 | ta_status.poly_context[2] = data[3].i; |
nkeynes@736 | 705 | ta_status.poly_context[4] = data[5].i; |
nkeynes@736 | 706 | if( data[0].i & TA_POLYCMD_SPECULAR ) { |
nkeynes@736 | 707 | ta_status.poly_context[0] |= 0x01000000; |
nkeynes@736 | 708 | ta_status.poly_vertex_size = 4; |
nkeynes@736 | 709 | } else { |
nkeynes@736 | 710 | ta_status.poly_vertex_size = 3; |
nkeynes@736 | 711 | } |
nkeynes@736 | 712 | if( data[0].i & TA_POLYCMD_UV16 ) { |
nkeynes@736 | 713 | ta_status.poly_vertex_size--; |
nkeynes@736 | 714 | } |
nkeynes@189 | 715 | } else { |
nkeynes@736 | 716 | ta_status.current_vertex_type = 0; |
nkeynes@736 | 717 | ta_status.poly_vertex_size = 1; |
nkeynes@736 | 718 | ta_status.poly_context[2] = 0; |
nkeynes@736 | 719 | ta_status.poly_context[4] = 0; |
nkeynes@189 | 720 | } |
nkeynes@189 | 721 | |
nkeynes@189 | 722 | ta_status.poly_pointer = (ta_status.poly_vertex_size << 21); |
nkeynes@189 | 723 | ta_status.poly_context_size = 3; |
nkeynes@189 | 724 | if( data[0].i & TA_POLYCMD_MODIFIED ) { |
nkeynes@736 | 725 | ta_status.poly_pointer |= 0x01000000; |
nkeynes@736 | 726 | if( data[0].i & TA_POLYCMD_FULLMOD ) { |
nkeynes@736 | 727 | ta_status.poly_context_size = 5; |
nkeynes@736 | 728 | ta_status.poly_vertex_size <<= 1; |
nkeynes@736 | 729 | ta_status.current_vertex_type |= 0x40; |
nkeynes@736 | 730 | /* Modified/float not supported - behaves as per last intensity */ |
nkeynes@736 | 731 | if( colourfmt == TA_POLYCMD_COLOURFMT_FLOAT ) { |
nkeynes@736 | 732 | colourfmt = TA_POLYCMD_COLOURFMT_LASTINT; |
nkeynes@736 | 733 | } |
nkeynes@736 | 734 | } |
nkeynes@189 | 735 | } |
nkeynes@736 | 736 | |
nkeynes@189 | 737 | if( colourfmt == TA_POLYCMD_COLOURFMT_INTENSITY ) { |
nkeynes@736 | 738 | if( TA_POLYCMD_IS_FULLMOD(data[0].i) || |
nkeynes@736 | 739 | TA_POLYCMD_IS_SPECULAR(data[0].i) ) { |
nkeynes@736 | 740 | ta_status.state = STATE_EXPECT_POLY_BLOCK2; |
nkeynes@736 | 741 | } else { |
nkeynes@736 | 742 | ta_status.intensity1 = |
nkeynes@736 | 743 | parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f ); |
nkeynes@736 | 744 | } |
nkeynes@189 | 745 | } else if( colourfmt == TA_POLYCMD_COLOURFMT_LASTINT ) { |
nkeynes@736 | 746 | colourfmt = TA_POLYCMD_COLOURFMT_INTENSITY; |
nkeynes@189 | 747 | } |
nkeynes@189 | 748 | |
nkeynes@189 | 749 | ta_status.current_vertex_type |= colourfmt; |
nkeynes@189 | 750 | } |
nkeynes@189 | 751 | |
nkeynes@189 | 752 | /** |
nkeynes@189 | 753 | * Parse the modifier volume context block and setup the internal state to |
nkeynes@189 | 754 | * receive modifier vertexes. |
nkeynes@189 | 755 | * @param data 32 bytes of parameter data. |
nkeynes@189 | 756 | */ |
nkeynes@189 | 757 | static void ta_parse_modifier_context( union ta_data *data ) { |
nkeynes@189 | 758 | ta_status.current_vertex_type = TA_VERTEX_MOD_VOLUME; |
nkeynes@189 | 759 | ta_status.poly_vertex_size = 0; |
nkeynes@206 | 760 | ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i); |
nkeynes@206 | 761 | if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */ |
nkeynes@736 | 762 | ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE; |
nkeynes@206 | 763 | } |
nkeynes@189 | 764 | ta_status.poly_context_size = 3; |
nkeynes@189 | 765 | ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) | |
nkeynes@736 | 766 | ((data[0].i & 0x0B)<<22); |
nkeynes@189 | 767 | if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) { |
nkeynes@736 | 768 | ta_status.poly_context[0] |= 0x01000000; |
nkeynes@189 | 769 | } |
nkeynes@189 | 770 | ta_status.poly_context[1] = 0; |
nkeynes@189 | 771 | ta_status.poly_context[2] = 0; |
nkeynes@189 | 772 | ta_status.vertex_count = 0; |
nkeynes@189 | 773 | ta_status.max_vertex = 3; |
nkeynes@189 | 774 | ta_status.poly_pointer = 0; |
nkeynes@189 | 775 | } |
nkeynes@189 | 776 | |
nkeynes@189 | 777 | /** |
nkeynes@189 | 778 | * Parse the sprite context block and setup the internal state to receive |
nkeynes@189 | 779 | * vertexes. |
nkeynes@189 | 780 | * @param data 32 bytes of parameter data. |
nkeynes@189 | 781 | */ |
nkeynes@189 | 782 | static void ta_parse_sprite_context( union ta_data *data ) { |
nkeynes@189 | 783 | ta_status.poly_context_size = 3; |
nkeynes@189 | 784 | ta_status.poly_context[0] = (data[1].i & 0xFC1FFFFF) | |
nkeynes@736 | 785 | ((data[0].i & 0x0B)<<22) | 0x00400000; |
nkeynes@340 | 786 | ta_status.clip_mode = TA_POLYCMD_CLIP(data[0].i); |
nkeynes@340 | 787 | if( ta_status.clip_mode == 1 ) { /* Reserved - treat as CLIP_INSIDE */ |
nkeynes@736 | 788 | ta_status.clip_mode = TA_POLYCMD_CLIP_INSIDE; |
nkeynes@340 | 789 | } |
nkeynes@189 | 790 | if( TA_POLYCMD_IS_SPECULAR(data[0].i) ) { |
nkeynes@736 | 791 | ta_status.poly_context[0] |= 0x01000000; |
nkeynes@189 | 792 | } |
nkeynes@189 | 793 | ta_status.poly_context[1] = data[2].i; |
nkeynes@189 | 794 | ta_status.poly_context[2] = data[3].i; |
nkeynes@189 | 795 | if( data[0].i & TA_POLYCMD_TEXTURED ) { |
nkeynes@736 | 796 | ta_status.poly_vertex_size = 2; |
nkeynes@736 | 797 | ta_status.poly_vertex[2].detail[1] = data[4].i; |
nkeynes@736 | 798 | ta_status.current_vertex_type = TA_VERTEX_TEX_SPRITE; |
nkeynes@189 | 799 | } else { |
nkeynes@736 | 800 | ta_status.poly_vertex_size = 1; |
nkeynes@736 | 801 | ta_status.poly_vertex[2].detail[0] = data[4].i; |
nkeynes@736 | 802 | ta_status.current_vertex_type = TA_VERTEX_SPRITE; |
nkeynes@189 | 803 | } |
nkeynes@189 | 804 | ta_status.vertex_count = 0; |
nkeynes@189 | 805 | ta_status.max_vertex = 4; |
nkeynes@189 | 806 | ta_status.poly_pointer = (ta_status.poly_vertex_size << 21); |
nkeynes@189 | 807 | } |
nkeynes@189 | 808 | |
nkeynes@189 | 809 | /** |
nkeynes@189 | 810 | * Copy the last read vertex into all vertexes up to max_vertex. Used for |
nkeynes@189 | 811 | * Aborted polygons under some circumstances. |
nkeynes@189 | 812 | */ |
nkeynes@189 | 813 | static void ta_fill_vertexes( ) { |
nkeynes@189 | 814 | int i; |
nkeynes@189 | 815 | for( i=ta_status.vertex_count; i<ta_status.max_vertex; i++ ) { |
nkeynes@736 | 816 | memcpy( &ta_status.poly_vertex[i], &ta_status.poly_vertex[ta_status.vertex_count-1], |
nkeynes@736 | 817 | sizeof( struct pvr2_ta_vertex ) ); |
nkeynes@189 | 818 | } |
nkeynes@189 | 819 | } |
nkeynes@189 | 820 | |
nkeynes@189 | 821 | static void ta_parse_vertex( union ta_data *data ) { |
nkeynes@189 | 822 | struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count]; |
nkeynes@189 | 823 | vertex->x = data[1].f; |
nkeynes@189 | 824 | vertex->y = data[2].f; |
nkeynes@189 | 825 | vertex->z = data[3].f; |
nkeynes@189 | 826 | |
nkeynes@189 | 827 | switch( ta_status.current_vertex_type ) { |
nkeynes@189 | 828 | case TA_VERTEX_PACKED: |
nkeynes@736 | 829 | vertex->detail[0] = data[6].i; |
nkeynes@736 | 830 | break; |
nkeynes@189 | 831 | case TA_VERTEX_FLOAT: |
nkeynes@736 | 832 | vertex->detail[0] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f ); |
nkeynes@736 | 833 | break; |
nkeynes@189 | 834 | case TA_VERTEX_INTENSITY: |
nkeynes@736 | 835 | vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[6].f ); |
nkeynes@736 | 836 | break; |
nkeynes@189 | 837 | |
nkeynes@189 | 838 | case TA_VERTEX_TEX_SPEC_PACKED: |
nkeynes@736 | 839 | vertex->detail[3] = data[7].i; /* ARGB */ |
nkeynes@736 | 840 | /* Fallthrough */ |
nkeynes@189 | 841 | case TA_VERTEX_TEX_PACKED: |
nkeynes@736 | 842 | vertex->detail[0] = data[4].i; /* U */ |
nkeynes@736 | 843 | vertex->detail[1] = data[5].i; /* V */ |
nkeynes@736 | 844 | vertex->detail[2] = data[6].i; /* ARGB */ |
nkeynes@736 | 845 | break; |
nkeynes@189 | 846 | case TA_VERTEX_TEX_UV16_SPEC_PACKED: |
nkeynes@736 | 847 | vertex->detail[2] = data[7].i; /* ARGB */ |
nkeynes@736 | 848 | /* Fallthrough */ |
nkeynes@189 | 849 | case TA_VERTEX_TEX_UV16_PACKED: |
nkeynes@736 | 850 | vertex->detail[0] = data[4].i; /* UV */ |
nkeynes@736 | 851 | vertex->detail[1] = data[6].i; /* ARGB */ |
nkeynes@736 | 852 | break; |
nkeynes@189 | 853 | |
nkeynes@189 | 854 | case TA_VERTEX_TEX_FLOAT: |
nkeynes@189 | 855 | case TA_VERTEX_TEX_SPEC_FLOAT: |
nkeynes@736 | 856 | vertex->detail[0] = data[4].i; /* U */ |
nkeynes@736 | 857 | vertex->detail[1] = data[5].i; /* UV */ |
nkeynes@736 | 858 | ta_status.state = STATE_EXPECT_VERTEX_BLOCK2; |
nkeynes@736 | 859 | break; |
nkeynes@189 | 860 | case TA_VERTEX_TEX_UV16_FLOAT: |
nkeynes@189 | 861 | case TA_VERTEX_TEX_UV16_SPEC_FLOAT: |
nkeynes@736 | 862 | vertex->detail[0] = data[4].i; /* UV */ |
nkeynes@736 | 863 | ta_status.state = STATE_EXPECT_VERTEX_BLOCK2; |
nkeynes@736 | 864 | break; |
nkeynes@189 | 865 | |
nkeynes@189 | 866 | case TA_VERTEX_TEX_SPEC_INTENSITY: |
nkeynes@736 | 867 | vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[7].f ); |
nkeynes@736 | 868 | /* Fallthrough */ |
nkeynes@189 | 869 | case TA_VERTEX_TEX_INTENSITY: |
nkeynes@736 | 870 | vertex->detail[0] = data[4].i; /* U */ |
nkeynes@736 | 871 | vertex->detail[1] = data[5].i; /* V */ |
nkeynes@736 | 872 | vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f ); |
nkeynes@736 | 873 | break; |
nkeynes@189 | 874 | case TA_VERTEX_TEX_UV16_SPEC_INTENSITY: |
nkeynes@736 | 875 | vertex->detail[2] = parse_intensity_colour( ta_status.intensity2, data[7].f ); |
nkeynes@736 | 876 | /* Fallthrough */ |
nkeynes@189 | 877 | case TA_VERTEX_TEX_UV16_INTENSITY: |
nkeynes@736 | 878 | vertex->detail[0] = data[4].i; /* UV */ |
nkeynes@736 | 879 | vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f ); |
nkeynes@736 | 880 | break; |
nkeynes@189 | 881 | |
nkeynes@189 | 882 | case TA_VERTEX_PACKED_MOD: |
nkeynes@736 | 883 | vertex->detail[0] = data[4].i; /* ARGB */ |
nkeynes@736 | 884 | vertex->detail[1] = data[5].i; /* ARGB */ |
nkeynes@736 | 885 | break; |
nkeynes@189 | 886 | case TA_VERTEX_INTENSITY_MOD: |
nkeynes@736 | 887 | vertex->detail[0] = parse_intensity_colour( ta_status.intensity1, data[4].f ); |
nkeynes@736 | 888 | vertex->detail[1] = parse_intensity_colour( ta_status.intensity2, data[5].f ); |
nkeynes@736 | 889 | break; |
nkeynes@189 | 890 | |
nkeynes@189 | 891 | case TA_VERTEX_TEX_SPEC_PACKED_MOD: |
nkeynes@736 | 892 | vertex->detail[3] = data[7].i; /* ARGB0 */ |
nkeynes@736 | 893 | /* Fallthrough */ |
nkeynes@189 | 894 | case TA_VERTEX_TEX_PACKED_MOD: |
nkeynes@736 | 895 | vertex->detail[0] = data[4].i; /* U0 */ |
nkeynes@736 | 896 | vertex->detail[1] = data[5].i; /* V0 */ |
nkeynes@736 | 897 | vertex->detail[2] = data[6].i; /* ARGB0 */ |
nkeynes@736 | 898 | ta_status.state = STATE_EXPECT_VERTEX_BLOCK2; |
nkeynes@736 | 899 | break; |
nkeynes@189 | 900 | case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD: |
nkeynes@736 | 901 | vertex->detail[2] = data[7].i; /* ARGB0 */ |
nkeynes@736 | 902 | /* Fallthrough */ |
nkeynes@189 | 903 | case TA_VERTEX_TEX_UV16_PACKED_MOD: |
nkeynes@736 | 904 | vertex->detail[0] = data[4].i; /* UV0 */ |
nkeynes@736 | 905 | vertex->detail[1] = data[6].i; /* ARGB0 */ |
nkeynes@736 | 906 | ta_status.state = STATE_EXPECT_VERTEX_BLOCK2; |
nkeynes@736 | 907 | break; |
nkeynes@189 | 908 | |
nkeynes@189 | 909 | case TA_VERTEX_TEX_SPEC_INTENSITY_MOD: |
nkeynes@736 | 910 | vertex->detail[3] = parse_intensity_colour( ta_status.intensity1, data[7].f ); |
nkeynes@736 | 911 | /* Fallthrough */ |
nkeynes@189 | 912 | case TA_VERTEX_TEX_INTENSITY_MOD: |
nkeynes@736 | 913 | vertex->detail[0] = data[4].i; /* U0 */ |
nkeynes@736 | 914 | vertex->detail[1] = data[5].i; /* V0 */ |
nkeynes@736 | 915 | vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[6].f ); |
nkeynes@736 | 916 | ta_status.state = STATE_EXPECT_VERTEX_BLOCK2; |
nkeynes@736 | 917 | break; |
nkeynes@189 | 918 | case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD: |
nkeynes@736 | 919 | vertex->detail[2] = parse_intensity_colour( ta_status.intensity1, data[7].f ); |
nkeynes@736 | 920 | /* Fallthrough */ |
nkeynes@189 | 921 | case TA_VERTEX_TEX_UV16_INTENSITY_MOD: |
nkeynes@736 | 922 | vertex->detail[0] = data[4].i; /* UV0 */ |
nkeynes@736 | 923 | vertex->detail[1] = parse_intensity_colour( ta_status.intensity1, data[6].f ); |
nkeynes@736 | 924 | ta_status.state = STATE_EXPECT_VERTEX_BLOCK2; |
nkeynes@736 | 925 | break; |
nkeynes@736 | 926 | |
nkeynes@189 | 927 | case TA_VERTEX_SPRITE: |
nkeynes@189 | 928 | case TA_VERTEX_TEX_SPRITE: |
nkeynes@189 | 929 | case TA_VERTEX_MOD_VOLUME: |
nkeynes@206 | 930 | case TA_VERTEX_LISTLESS: |
nkeynes@736 | 931 | vertex++; |
nkeynes@736 | 932 | vertex->x = data[4].f; |
nkeynes@736 | 933 | vertex->y = data[5].f; |
nkeynes@736 | 934 | vertex->z = data[6].f; |
nkeynes@736 | 935 | vertex++; |
nkeynes@736 | 936 | vertex->x = data[7].f; |
nkeynes@736 | 937 | ta_status.vertex_count += 2; |
nkeynes@736 | 938 | ta_status.state = STATE_EXPECT_VERTEX_BLOCK2; |
nkeynes@736 | 939 | break; |
nkeynes@189 | 940 | } |
nkeynes@189 | 941 | ta_status.vertex_count++; |
nkeynes@189 | 942 | } |
nkeynes@189 | 943 | |
nkeynes@189 | 944 | static void ta_parse_vertex_block2( union ta_data *data ) { |
nkeynes@189 | 945 | struct pvr2_ta_vertex *vertex = &ta_status.poly_vertex[ta_status.vertex_count-1]; |
nkeynes@189 | 946 | |
nkeynes@189 | 947 | switch( ta_status.current_vertex_type ) { |
nkeynes@189 | 948 | case TA_VERTEX_TEX_SPEC_FLOAT: |
nkeynes@736 | 949 | vertex->detail[3] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f ); |
nkeynes@736 | 950 | /* Fallthrough */ |
nkeynes@189 | 951 | case TA_VERTEX_TEX_FLOAT: |
nkeynes@736 | 952 | vertex->detail[2] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f ); |
nkeynes@736 | 953 | break; |
nkeynes@189 | 954 | case TA_VERTEX_TEX_UV16_SPEC_FLOAT: |
nkeynes@736 | 955 | vertex->detail[2] = parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f ); |
nkeynes@736 | 956 | /* Fallthrough */ |
nkeynes@189 | 957 | case TA_VERTEX_TEX_UV16_FLOAT: |
nkeynes@736 | 958 | vertex->detail[1] = parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f ); |
nkeynes@736 | 959 | break; |
nkeynes@189 | 960 | case TA_VERTEX_TEX_PACKED_MOD: |
nkeynes@736 | 961 | vertex->detail[3] = data[0].i; /* U1 */ |
nkeynes@736 | 962 | vertex->detail[4] = data[1].i; /* V1 */ |
nkeynes@736 | 963 | vertex->detail[5] = data[2].i; /* ARGB1 */ |
nkeynes@736 | 964 | break; |
nkeynes@189 | 965 | case TA_VERTEX_TEX_SPEC_PACKED_MOD: |
nkeynes@736 | 966 | vertex->detail[4] = data[0].i; /* U1 */ |
nkeynes@736 | 967 | vertex->detail[5] = data[1].i; /* V1 */ |
nkeynes@736 | 968 | vertex->detail[6] = data[2].i; /* ARGB1 */ |
nkeynes@736 | 969 | vertex->detail[7] = data[3].i; /* ARGB1 */ |
nkeynes@736 | 970 | break; |
nkeynes@189 | 971 | case TA_VERTEX_TEX_UV16_PACKED_MOD: |
nkeynes@736 | 972 | vertex->detail[2] = data[0].i; /* UV1 */ |
nkeynes@736 | 973 | vertex->detail[3] = data[2].i; /* ARGB1 */ |
nkeynes@736 | 974 | break; |
nkeynes@189 | 975 | case TA_VERTEX_TEX_UV16_SPEC_PACKED_MOD: |
nkeynes@736 | 976 | vertex->detail[3] = data[0].i; /* UV1 */ |
nkeynes@736 | 977 | vertex->detail[4] = data[2].i; /* ARGB1 */ |
nkeynes@736 | 978 | vertex->detail[5] = data[3].i; /* ARGB1 */ |
nkeynes@736 | 979 | break; |
nkeynes@189 | 980 | |
nkeynes@189 | 981 | case TA_VERTEX_TEX_INTENSITY_MOD: |
nkeynes@736 | 982 | vertex->detail[3] = data[0].i; /* U1 */ |
nkeynes@736 | 983 | vertex->detail[4] = data[1].i; /* V1 */ |
nkeynes@736 | 984 | vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */ |
nkeynes@736 | 985 | break; |
nkeynes@189 | 986 | case TA_VERTEX_TEX_SPEC_INTENSITY_MOD: |
nkeynes@736 | 987 | vertex->detail[4] = data[0].i; /* U1 */ |
nkeynes@736 | 988 | vertex->detail[5] = data[1].i; /* V1 */ |
nkeynes@736 | 989 | vertex->detail[6] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */ |
nkeynes@736 | 990 | vertex->detail[7] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */ |
nkeynes@736 | 991 | break; |
nkeynes@189 | 992 | case TA_VERTEX_TEX_UV16_INTENSITY_MOD: |
nkeynes@736 | 993 | vertex->detail[2] = data[0].i; /* UV1 */ |
nkeynes@736 | 994 | vertex->detail[3] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */ |
nkeynes@736 | 995 | break; |
nkeynes@189 | 996 | case TA_VERTEX_TEX_UV16_SPEC_INTENSITY_MOD: |
nkeynes@736 | 997 | vertex->detail[3] = data[0].i; /* UV1 */ |
nkeynes@736 | 998 | vertex->detail[4] = parse_intensity_colour( ta_status.intensity2, data[2].f ); /* ARGB1 */ |
nkeynes@736 | 999 | vertex->detail[5] = parse_intensity_colour( ta_status.intensity2, data[3].f ); /* ARGB1 */ |
nkeynes@736 | 1000 | break; |
nkeynes@189 | 1001 | |
nkeynes@189 | 1002 | case TA_VERTEX_SPRITE: |
nkeynes@736 | 1003 | vertex->y = data[0].f; |
nkeynes@736 | 1004 | vertex->z = data[1].f; |
nkeynes@736 | 1005 | vertex++; |
nkeynes@736 | 1006 | ta_status.vertex_count++; |
nkeynes@736 | 1007 | vertex->x = data[2].f; |
nkeynes@736 | 1008 | vertex->y = data[3].f; |
nkeynes@736 | 1009 | vertex->z = 0; |
nkeynes@736 | 1010 | vertex->detail[0] = 0; |
nkeynes@736 | 1011 | ta_status.poly_vertex[0].detail[0] = 0; |
nkeynes@736 | 1012 | ta_status.poly_vertex[1].detail[0] = 0; |
nkeynes@736 | 1013 | break; |
nkeynes@189 | 1014 | case TA_VERTEX_TEX_SPRITE: |
nkeynes@736 | 1015 | vertex->y = data[0].f; |
nkeynes@736 | 1016 | vertex->z = data[1].f; |
nkeynes@736 | 1017 | vertex++; |
nkeynes@736 | 1018 | ta_status.vertex_count++; |
nkeynes@736 | 1019 | vertex->x = data[2].f; |
nkeynes@736 | 1020 | vertex->y = data[3].f; |
nkeynes@736 | 1021 | vertex->z = 0; |
nkeynes@736 | 1022 | vertex->detail[0] = 0; |
nkeynes@736 | 1023 | vertex->detail[1] = 0; |
nkeynes@736 | 1024 | ta_status.poly_vertex[0].detail[0] = data[5].i; |
nkeynes@736 | 1025 | ta_status.poly_vertex[0].detail[1] = 0; |
nkeynes@736 | 1026 | ta_status.poly_vertex[1].detail[0] = data[6].i; |
nkeynes@736 | 1027 | ta_status.poly_vertex[1].detail[1] = 0; |
nkeynes@736 | 1028 | ta_status.poly_vertex[2].detail[0] = data[7].i; |
nkeynes@736 | 1029 | break; |
nkeynes@189 | 1030 | case TA_VERTEX_MOD_VOLUME: |
nkeynes@206 | 1031 | case TA_VERTEX_LISTLESS: |
nkeynes@736 | 1032 | vertex->y = data[0].f; |
nkeynes@736 | 1033 | vertex->z = data[1].f; |
nkeynes@736 | 1034 | break; |
nkeynes@189 | 1035 | } |
nkeynes@194 | 1036 | ta_status.state = STATE_IN_POLYGON; |
nkeynes@189 | 1037 | } |
nkeynes@189 | 1038 | |
nkeynes@189 | 1039 | /** |
nkeynes@189 | 1040 | * Process 1 32-byte block of ta data |
nkeynes@189 | 1041 | */ |
nkeynes@429 | 1042 | void pvr2_ta_process_block( unsigned char *input ) { |
nkeynes@189 | 1043 | union ta_data *data = (union ta_data *)input; |
nkeynes@189 | 1044 | |
nkeynes@189 | 1045 | switch( ta_status.state ) { |
nkeynes@189 | 1046 | case STATE_ERROR: |
nkeynes@736 | 1047 | /* Fatal error raised - stop processing until reset */ |
nkeynes@736 | 1048 | return; |
nkeynes@189 | 1049 | |
nkeynes@189 | 1050 | case STATE_EXPECT_POLY_BLOCK2: |
nkeynes@736 | 1051 | /* This is always a pair of floating-point colours */ |
nkeynes@736 | 1052 | ta_status.intensity1 = |
nkeynes@736 | 1053 | parse_float_colour( data[0].f, data[1].f, data[2].f, data[3].f ); |
nkeynes@736 | 1054 | ta_status.intensity2 = |
nkeynes@736 | 1055 | parse_float_colour( data[4].f, data[5].f, data[6].f, data[7].f ); |
nkeynes@736 | 1056 | ta_status.state = STATE_IN_LIST; |
nkeynes@736 | 1057 | break; |
nkeynes@189 | 1058 | |
nkeynes@189 | 1059 | case STATE_EXPECT_VERTEX_BLOCK2: |
nkeynes@736 | 1060 | ta_parse_vertex_block2( data ); |
nkeynes@736 | 1061 | if( ta_status.vertex_count == ta_status.max_vertex ) { |
nkeynes@736 | 1062 | ta_split_polygon(); |
nkeynes@736 | 1063 | } |
nkeynes@736 | 1064 | break; |
nkeynes@189 | 1065 | |
nkeynes@189 | 1066 | case STATE_EXPECT_END_VERTEX_BLOCK2: |
nkeynes@736 | 1067 | ta_parse_vertex_block2( data ); |
nkeynes@736 | 1068 | if( ta_status.vertex_count < 3 ) { |
nkeynes@736 | 1069 | ta_bad_input_error(); |
nkeynes@736 | 1070 | } else { |
nkeynes@736 | 1071 | ta_commit_polygon(); |
nkeynes@736 | 1072 | } |
nkeynes@736 | 1073 | ta_status.vertex_count = 0; |
nkeynes@736 | 1074 | ta_status.poly_parity = 0; |
nkeynes@736 | 1075 | ta_status.state = STATE_IN_LIST; |
nkeynes@736 | 1076 | break; |
nkeynes@189 | 1077 | case STATE_IN_LIST: |
nkeynes@194 | 1078 | case STATE_IN_POLYGON: |
nkeynes@189 | 1079 | case STATE_IDLE: |
nkeynes@736 | 1080 | switch( TA_CMD( data->i ) ) { |
nkeynes@736 | 1081 | case TA_CMD_END_LIST: |
nkeynes@736 | 1082 | if( ta_status.state == STATE_IN_POLYGON ) { |
nkeynes@736 | 1083 | ta_bad_input_error(); |
nkeynes@736 | 1084 | ta_end_list(); |
nkeynes@736 | 1085 | ta_status.state = STATE_ERROR; /* Abort further processing */ |
nkeynes@736 | 1086 | } else { |
nkeynes@736 | 1087 | ta_end_list(); |
nkeynes@736 | 1088 | } |
nkeynes@736 | 1089 | break; |
nkeynes@736 | 1090 | case TA_CMD_CLIP: |
nkeynes@736 | 1091 | if( ta_status.state == STATE_IN_POLYGON ) { |
nkeynes@736 | 1092 | ta_bad_input_error(); |
nkeynes@736 | 1093 | ta_status.accept_vertexes = FALSE; |
nkeynes@736 | 1094 | /* Enter stuffed up mode */ |
nkeynes@736 | 1095 | } |
nkeynes@736 | 1096 | ta_status.clip.x1 = data[4].i & 0x3F; |
nkeynes@736 | 1097 | ta_status.clip.y1 = data[5].i & 0x0F; |
nkeynes@736 | 1098 | ta_status.clip.x2 = data[6].i & 0x3F; |
nkeynes@736 | 1099 | ta_status.clip.y2 = data[7].i & 0x0F; |
nkeynes@736 | 1100 | if( ta_status.clip.x2 >= ta_status.width ) |
nkeynes@736 | 1101 | ta_status.clip.x2 = ta_status.width - 1; |
nkeynes@736 | 1102 | if( ta_status.clip.y2 >= ta_status.height ) |
nkeynes@736 | 1103 | ta_status.clip.y2 = ta_status.height - 1; |
nkeynes@736 | 1104 | break; |
nkeynes@736 | 1105 | case TA_CMD_POLYGON_CONTEXT: |
nkeynes@736 | 1106 | if( ta_status.state == STATE_IDLE ) { |
nkeynes@736 | 1107 | ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) ); |
nkeynes@736 | 1108 | } |
nkeynes@189 | 1109 | |
nkeynes@736 | 1110 | if( ta_status.vertex_count != 0 ) { |
nkeynes@736 | 1111 | /* Error, and not a very well handled one either */ |
nkeynes@736 | 1112 | ta_bad_input_error(); |
nkeynes@736 | 1113 | ta_status.accept_vertexes = FALSE; |
nkeynes@736 | 1114 | } else { |
nkeynes@736 | 1115 | if( TA_IS_MODIFIER_LIST( ta_status.current_list_type ) ) { |
nkeynes@736 | 1116 | ta_parse_modifier_context(data); |
nkeynes@736 | 1117 | } else { |
nkeynes@736 | 1118 | ta_parse_polygon_context(data); |
nkeynes@736 | 1119 | } |
nkeynes@736 | 1120 | } |
nkeynes@736 | 1121 | break; |
nkeynes@736 | 1122 | case TA_CMD_SPRITE_CONTEXT: |
nkeynes@736 | 1123 | if( ta_status.state == STATE_IDLE ) { |
nkeynes@736 | 1124 | ta_init_list( TA_POLYCMD_LISTTYPE( data->i ) ); |
nkeynes@736 | 1125 | } |
nkeynes@189 | 1126 | |
nkeynes@736 | 1127 | if( ta_status.vertex_count != 0 ) { |
nkeynes@736 | 1128 | ta_fill_vertexes(); |
nkeynes@736 | 1129 | ta_commit_polygon(); |
nkeynes@736 | 1130 | } |
nkeynes@736 | 1131 | |
nkeynes@736 | 1132 | ta_parse_sprite_context(data); |
nkeynes@736 | 1133 | break; |
nkeynes@736 | 1134 | case TA_CMD_VERTEX: |
nkeynes@736 | 1135 | ta_status.state = STATE_IN_POLYGON; |
nkeynes@736 | 1136 | ta_parse_vertex(data); |
nkeynes@736 | 1137 | |
nkeynes@736 | 1138 | if( ta_status.state == STATE_EXPECT_VERTEX_BLOCK2 ) { |
nkeynes@736 | 1139 | if( TA_IS_END_VERTEX(data[0].i) ) { |
nkeynes@736 | 1140 | ta_status.state = STATE_EXPECT_END_VERTEX_BLOCK2; |
nkeynes@736 | 1141 | } |
nkeynes@736 | 1142 | } else if( TA_IS_END_VERTEX(data->i) ) { |
nkeynes@736 | 1143 | if( ta_status.vertex_count < 3 ) { |
nkeynes@736 | 1144 | ta_bad_input_error(); |
nkeynes@736 | 1145 | } else { |
nkeynes@736 | 1146 | ta_commit_polygon(); |
nkeynes@736 | 1147 | } |
nkeynes@736 | 1148 | ta_status.vertex_count = 0; |
nkeynes@736 | 1149 | ta_status.poly_parity = 0; |
nkeynes@736 | 1150 | ta_status.state = STATE_IN_LIST; |
nkeynes@736 | 1151 | } else if( ta_status.vertex_count == ta_status.max_vertex ) { |
nkeynes@736 | 1152 | ta_split_polygon(); |
nkeynes@736 | 1153 | } |
nkeynes@736 | 1154 | break; |
nkeynes@736 | 1155 | default: |
nkeynes@736 | 1156 | if( ta_status.state == STATE_IN_POLYGON ) { |
nkeynes@736 | 1157 | ta_bad_input_error(); |
nkeynes@736 | 1158 | } |
nkeynes@736 | 1159 | } |
nkeynes@736 | 1160 | break; |
nkeynes@189 | 1161 | } |
nkeynes@189 | 1162 | |
nkeynes@189 | 1163 | } |
nkeynes@189 | 1164 | |
nkeynes@753 | 1165 | /** |
nkeynes@753 | 1166 | * Find the first polygon or sprite context in the supplied buffer of TA |
nkeynes@753 | 1167 | * data. |
nkeynes@753 | 1168 | * @return A pointer to the context, or NULL if it cannot be found |
nkeynes@753 | 1169 | */ |
nkeynes@753 | 1170 | uint32_t *pvr2_ta_find_polygon_context( uint32_t *buf, uint32_t length ) |
nkeynes@753 | 1171 | { |
nkeynes@753 | 1172 | uint32_t *poly; |
nkeynes@753 | 1173 | for( poly = buf; poly < buf+(length>>2); poly += 8 ) { |
nkeynes@753 | 1174 | if( TA_CMD(*poly) == TA_CMD_POLYGON_CONTEXT || |
nkeynes@753 | 1175 | TA_CMD(*poly) == TA_CMD_SPRITE_CONTEXT ) { |
nkeynes@753 | 1176 | return poly; |
nkeynes@753 | 1177 | } |
nkeynes@753 | 1178 | } |
nkeynes@753 | 1179 | return NULL; |
nkeynes@753 | 1180 | } |
nkeynes@189 | 1181 | |
nkeynes@189 | 1182 | /** |
nkeynes@189 | 1183 | * Write a block of data to the tile accelerator, adding the data to the |
nkeynes@189 | 1184 | * current scene. We don't make any particular attempt to interpret the data |
nkeynes@189 | 1185 | * at this stage, deferring that until render time. |
nkeynes@189 | 1186 | * |
nkeynes@189 | 1187 | * Currently copies the data verbatim to the vertex buffer, processing only |
nkeynes@189 | 1188 | * far enough to generate the correct end-of-list events. Tile buffer is |
nkeynes@189 | 1189 | * entirely ignored. |
nkeynes@189 | 1190 | */ |
nkeynes@429 | 1191 | void pvr2_ta_write( unsigned char *buf, uint32_t length ) |
nkeynes@189 | 1192 | { |
nkeynes@189 | 1193 | if( ta_status.debug_output ) { |
nkeynes@736 | 1194 | fwrite_dump32( (uint32_t *)buf, length, stderr ); |
nkeynes@189 | 1195 | } |
nkeynes@189 | 1196 | |
nkeynes@189 | 1197 | for( ; length >=32; length -= 32 ) { |
nkeynes@736 | 1198 | pvr2_ta_process_block( buf ); |
nkeynes@736 | 1199 | buf += 32; |
nkeynes@189 | 1200 | } |
nkeynes@189 | 1201 | } |
nkeynes@953 | 1202 | |
nkeynes@953 | 1203 | void FASTCALL pvr2_ta_write_burst( sh4addr_t addr, unsigned char *data ) |
nkeynes@953 | 1204 | { |
nkeynes@953 | 1205 | if( ta_status.debug_output ) { |
nkeynes@953 | 1206 | fwrite_dump32( (uint32_t *)data, 32, stderr ); |
nkeynes@953 | 1207 | } |
nkeynes@953 | 1208 | pvr2_ta_process_block( data ); |
nkeynes@953 | 1209 | } |
.