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