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