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