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