Search
lxdream.org :: lxdream/src/pvr2/rendcore.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/rendcore.c
changeset 561:533f6b478071
prev540:a3767018a96d
next635:76c63aac3590
author nkeynes
date Tue Jan 01 05:08:38 2008 +0000 (16 years ago)
branchlxdream-mmu
permissions -rw-r--r--
last change Enable Id keyword on all source files
file annotate diff log raw
nkeynes@189
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@189
     3
 *
nkeynes@189
     4
 * PVR2 renderer core.
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@215
    18
#include <sys/time.h>
nkeynes@189
    19
#include "pvr2/pvr2.h"
nkeynes@189
    20
#include "asic.h"
nkeynes@540
    21
#include "display.h"
nkeynes@429
    22
nkeynes@221
    23
int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
nkeynes@189
    24
				      GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, 
nkeynes@189
    25
				      GL_ALWAYS };
nkeynes@221
    26
int pvr2_poly_srcblend[8] = { 
nkeynes@189
    27
    GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
nkeynes@189
    28
    GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, 
nkeynes@189
    29
    GL_ONE_MINUS_DST_ALPHA };
nkeynes@221
    30
int pvr2_poly_dstblend[8] = {
nkeynes@189
    31
    GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
nkeynes@189
    32
    GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
nkeynes@189
    33
    GL_ONE_MINUS_DST_ALPHA };
nkeynes@221
    34
int pvr2_poly_texblend[4] = {
nkeynes@322
    35
    GL_REPLACE, 
nkeynes@322
    36
    GL_MODULATE,  
nkeynes@322
    37
    GL_DECAL, 
nkeynes@322
    38
    GL_MODULATE 
nkeynes@322
    39
};
nkeynes@221
    40
int pvr2_render_colour_format[8] = {
nkeynes@477
    41
    COLFMT_BGRA1555, COLFMT_RGB565, COLFMT_BGRA4444, COLFMT_BGRA1555,
nkeynes@477
    42
    COLFMT_BGR888, COLFMT_BGRA8888, COLFMT_BGRA8888, COLFMT_BGRA4444 };
nkeynes@189
    43
nkeynes@189
    44
nkeynes@189
    45
#define CULL_NONE 0
nkeynes@189
    46
#define CULL_SMALL 1
nkeynes@189
    47
#define CULL_CCW 2
nkeynes@189
    48
#define CULL_CW 3
nkeynes@189
    49
nkeynes@189
    50
#define SEGMENT_END         0x80000000
nkeynes@298
    51
#define SEGMENT_ZCLEAR      0x40000000
nkeynes@189
    52
#define SEGMENT_SORT_TRANS  0x20000000
nkeynes@189
    53
#define SEGMENT_START       0x10000000
nkeynes@189
    54
#define SEGMENT_X(c)        (((c) >> 2) & 0x3F)
nkeynes@189
    55
#define SEGMENT_Y(c)        (((c) >> 8) & 0x3F)
nkeynes@189
    56
#define NO_POINTER          0x80000000
nkeynes@189
    57
nkeynes@189
    58
extern char *video_base;
nkeynes@189
    59
nkeynes@322
    60
gboolean pvr2_force_fragment_alpha = FALSE;
nkeynes@338
    61
gboolean pvr2_debug_render = FALSE;
nkeynes@318
    62
nkeynes@189
    63
struct tile_segment {
nkeynes@189
    64
    uint32_t control;
nkeynes@189
    65
    pvraddr_t opaque_ptr;
nkeynes@189
    66
    pvraddr_t opaquemod_ptr;
nkeynes@189
    67
    pvraddr_t trans_ptr;
nkeynes@189
    68
    pvraddr_t transmod_ptr;
nkeynes@189
    69
    pvraddr_t punchout_ptr;
nkeynes@189
    70
};
nkeynes@189
    71
nkeynes@341
    72
void render_print_tilelist( FILE *f, uint32_t tile_entry );
nkeynes@341
    73
nkeynes@189
    74
/**
nkeynes@189
    75
 * Convert a half-float (16-bit) FP number to a regular 32-bit float.
nkeynes@189
    76
 * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
nkeynes@189
    77
 * TODO: Check the correctness of this.
nkeynes@189
    78
 */
nkeynes@189
    79
float halftofloat( uint16_t half )
nkeynes@189
    80
{
nkeynes@189
    81
    union {
nkeynes@189
    82
        float f;
nkeynes@189
    83
        uint32_t i;
nkeynes@189
    84
    } temp;
nkeynes@308
    85
    /* int e = ((half & 0x7C00) >> 10) - 15 + 127;
nkeynes@189
    86
nkeynes@189
    87
    temp.i = ((half & 0x8000) << 16) | (e << 23) |
nkeynes@308
    88
    ((half & 0x03FF) << 13); */
nkeynes@308
    89
    temp.i = ((uint32_t)half)<<16;
nkeynes@189
    90
    return temp.f;
nkeynes@189
    91
}
nkeynes@189
    92
nkeynes@189
    93
nkeynes@189
    94
/**
nkeynes@189
    95
 * Setup the GL context for the supplied polygon context.
nkeynes@189
    96
 * @param context pointer to 3 or 5 words of polygon context
nkeynes@189
    97
 * @param modified boolean flag indicating that the modified
nkeynes@189
    98
 *  version should be used, rather than the normal version.
nkeynes@189
    99
 */
nkeynes@189
   100
void render_set_context( uint32_t *context, int render_mode )
nkeynes@189
   101
{
nkeynes@189
   102
    uint32_t poly1 = context[0], poly2, texture;
nkeynes@189
   103
    if( render_mode == RENDER_FULLMOD ) {
nkeynes@189
   104
	poly2 = context[3];
nkeynes@189
   105
	texture = context[4];
nkeynes@189
   106
    } else {
nkeynes@189
   107
	poly2 = context[1];
nkeynes@189
   108
	texture = context[2];
nkeynes@189
   109
    }
nkeynes@338
   110
    
nkeynes@189
   111
    if( POLY1_DEPTH_ENABLE(poly1) ) {
nkeynes@189
   112
	glEnable( GL_DEPTH_TEST );
nkeynes@189
   113
	glDepthFunc( POLY1_DEPTH_MODE(poly1) );
nkeynes@189
   114
    } else {
nkeynes@189
   115
	glDisable( GL_DEPTH_TEST );
nkeynes@189
   116
    }
nkeynes@189
   117
    
nkeynes@189
   118
    switch( POLY1_CULL_MODE(poly1) ) {
nkeynes@189
   119
    case CULL_NONE:
nkeynes@189
   120
    case CULL_SMALL:
nkeynes@189
   121
	glDisable( GL_CULL_FACE );
nkeynes@189
   122
	break;
nkeynes@189
   123
    case CULL_CCW:
nkeynes@189
   124
	glEnable( GL_CULL_FACE );
nkeynes@189
   125
	glFrontFace( GL_CW );
nkeynes@189
   126
	break;
nkeynes@189
   127
    case CULL_CW:
nkeynes@189
   128
	glEnable( GL_CULL_FACE );
nkeynes@189
   129
	glFrontFace( GL_CCW );
nkeynes@189
   130
	break;
nkeynes@189
   131
    }
nkeynes@189
   132
nkeynes@318
   133
    if( POLY1_SPECULAR(poly1) ) {
nkeynes@318
   134
	glEnable(GL_COLOR_SUM);
nkeynes@318
   135
    } else {
nkeynes@318
   136
	glDisable(GL_COLOR_SUM);
nkeynes@318
   137
    }
nkeynes@318
   138
nkeynes@338
   139
    pvr2_force_fragment_alpha = POLY2_ALPHA_ENABLE(poly2) ? FALSE : TRUE;
nkeynes@338
   140
nkeynes@189
   141
    if( POLY1_TEXTURED(poly1) ) {
nkeynes@189
   142
	int width = POLY2_TEX_WIDTH(poly2);
nkeynes@189
   143
	int height = POLY2_TEX_HEIGHT(poly2);
nkeynes@189
   144
	glEnable(GL_TEXTURE_2D);
nkeynes@286
   145
	texcache_get_texture( (texture&0x000FFFFF)<<3, width, height, texture );
nkeynes@338
   146
	switch( POLY2_TEX_BLEND(poly2) ) {
nkeynes@338
   147
	case 0: /* Replace */
nkeynes@338
   148
	    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
nkeynes@338
   149
	    break;
nkeynes@338
   150
	case 2:/* Decal */
nkeynes@338
   151
	    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
nkeynes@338
   152
	    break;
nkeynes@338
   153
	case 1: /* Modulate RGB */
nkeynes@338
   154
	    /* This is not directly supported by opengl (other than by mucking
nkeynes@338
   155
	     * with the texture format), but we get the same effect by forcing
nkeynes@338
   156
	     * the fragment alpha to 1.0 and using GL_MODULATE.
nkeynes@338
   157
	     */
nkeynes@338
   158
	    pvr2_force_fragment_alpha = TRUE;
nkeynes@338
   159
	case 3: /* Modulate RGBA */
nkeynes@338
   160
	    glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
nkeynes@338
   161
	    break;
nkeynes@338
   162
	}
nkeynes@352
   163
nkeynes@308
   164
	if( POLY2_TEX_CLAMP_U(poly2) ) {
nkeynes@308
   165
	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
nkeynes@308
   166
	} else {
nkeynes@308
   167
	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
nkeynes@308
   168
	}	    
nkeynes@308
   169
	if( POLY2_TEX_CLAMP_V(poly2) ) {
nkeynes@308
   170
	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
nkeynes@308
   171
	} else {
nkeynes@350
   172
	    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
nkeynes@308
   173
	}
nkeynes@189
   174
    } else {
nkeynes@189
   175
	glDisable( GL_TEXTURE_2D );
nkeynes@189
   176
    }
nkeynes@189
   177
nkeynes@189
   178
    glShadeModel( POLY1_SHADE_MODEL(poly1) );
nkeynes@189
   179
nkeynes@221
   180
    int srcblend = POLY2_SRC_BLEND(poly2);
nkeynes@221
   181
    int destblend = POLY2_DEST_BLEND(poly2);
nkeynes@221
   182
    glBlendFunc( srcblend, destblend );
nkeynes@318
   183
nkeynes@322
   184
    if( POLY2_SRC_BLEND_TARGET(poly2) || POLY2_DEST_BLEND_TARGET(poly2) ) {
nkeynes@322
   185
	ERROR( "Accumulation buffer not supported" );
nkeynes@322
   186
    }
nkeynes@338
   187
nkeynes@318
   188
nkeynes@189
   189
}
nkeynes@189
   190
nkeynes@319
   191
#define FARGB_A(x) (((float)(((x)>>24)+1))/256.0)
nkeynes@319
   192
#define FARGB_R(x) (((float)((((x)>>16)&0xFF)+1))/256.0)
nkeynes@319
   193
#define FARGB_G(x) (((float)((((x)>>8)&0xFF)+1))/256.0)
nkeynes@319
   194
#define FARGB_B(x) (((float)(((x)&0xFF)+1))/256.0)
nkeynes@319
   195
nkeynes@319
   196
void render_unpack_vertexes( struct vertex_unpacked *out, uint32_t poly1, 
nkeynes@319
   197
			     uint32_t *vertexes, int num_vertexes,
nkeynes@319
   198
			     int vertex_size, int render_mode )
nkeynes@319
   199
{
nkeynes@319
   200
    int m = 0, i;
nkeynes@319
   201
    if( render_mode == RENDER_FULLMOD ) {
nkeynes@319
   202
	m = (vertex_size - 3)/2;
nkeynes@319
   203
    }
nkeynes@319
   204
nkeynes@319
   205
    for( i=0; i<num_vertexes; i++ ) {
nkeynes@319
   206
	float *vertexf = (float *)vertexes;
nkeynes@319
   207
	int k = m + 3;
nkeynes@319
   208
	out[i].x = vertexf[0];
nkeynes@319
   209
	out[i].y = vertexf[1];
nkeynes@319
   210
	out[i].z = vertexf[2];
nkeynes@319
   211
    	if( POLY1_TEXTURED(poly1) ) {
nkeynes@319
   212
	    if( POLY1_UV16(poly1) ) {
nkeynes@319
   213
		out[i].u = halftofloat(vertexes[k]>>16);
nkeynes@319
   214
		out[i].v = halftofloat(vertexes[k]);
nkeynes@319
   215
		k++;
nkeynes@319
   216
	    } else {
nkeynes@319
   217
		out[i].u = vertexf[k];
nkeynes@319
   218
		out[i].v = vertexf[k+1];
nkeynes@319
   219
		k+=2;
nkeynes@319
   220
	    }
nkeynes@319
   221
	} else {
nkeynes@319
   222
	    out[i].u = 0;
nkeynes@319
   223
	    out[i].v = 0;
nkeynes@319
   224
	}
nkeynes@319
   225
	uint32_t argb = vertexes[k++];
nkeynes@319
   226
	out[i].rgba[0] = FARGB_R(argb);
nkeynes@319
   227
	out[i].rgba[1] = FARGB_G(argb);
nkeynes@319
   228
        out[i].rgba[2] = FARGB_B(argb);
nkeynes@319
   229
	out[i].rgba[3] = FARGB_A(argb);
nkeynes@319
   230
	if( POLY1_SPECULAR(poly1) ) {
nkeynes@319
   231
	    uint32_t offset = vertexes[k++];
nkeynes@429
   232
	    out[i].offset_rgba[0] = FARGB_R(offset);
nkeynes@429
   233
	    out[i].offset_rgba[1] = FARGB_G(offset);
nkeynes@429
   234
	    out[i].offset_rgba[2] = FARGB_B(offset);
nkeynes@429
   235
	    out[i].offset_rgba[3] = FARGB_A(offset);
nkeynes@319
   236
	}
nkeynes@319
   237
	vertexes += vertex_size;
nkeynes@319
   238
    }
nkeynes@319
   239
}
nkeynes@319
   240
nkeynes@319
   241
/**
nkeynes@319
   242
 * Unpack the vertexes for a quad, calculating the values for the last
nkeynes@319
   243
 * vertex.
nkeynes@319
   244
 * FIXME: Integrate this with rendbkg somehow
nkeynes@319
   245
 */
nkeynes@319
   246
void render_unpack_quad( struct vertex_unpacked *unpacked, uint32_t poly1, 
nkeynes@319
   247
			 uint32_t *vertexes, int vertex_size,
nkeynes@319
   248
			 int render_mode )
nkeynes@319
   249
{
nkeynes@319
   250
    int i;
nkeynes@319
   251
    struct vertex_unpacked diff0, diff1;
nkeynes@319
   252
nkeynes@319
   253
    render_unpack_vertexes( unpacked, poly1, vertexes, 3, vertex_size, render_mode );
nkeynes@319
   254
    
nkeynes@319
   255
    diff0.x = unpacked[0].x - unpacked[1].x;
nkeynes@319
   256
    diff0.y = unpacked[0].y - unpacked[1].y;
nkeynes@319
   257
    diff1.x = unpacked[2].x - unpacked[1].x;
nkeynes@319
   258
    diff1.y = unpacked[2].y - unpacked[1].y;
nkeynes@319
   259
nkeynes@319
   260
    float detxy = ((diff1.y) * (diff0.x)) - ((diff0.y) * (diff1.x));
nkeynes@319
   261
    float *vertexf = (float *)(vertexes+(vertex_size*3));
nkeynes@319
   262
    if( detxy == 0 ) {
nkeynes@319
   263
	memcpy( &unpacked[3], &unpacked[2], sizeof(struct vertex_unpacked) );
nkeynes@319
   264
	unpacked[3].x = vertexf[0];
nkeynes@319
   265
	unpacked[3].y = vertexf[1];
nkeynes@319
   266
	return;
nkeynes@319
   267
    }	
nkeynes@319
   268
nkeynes@319
   269
    unpacked[3].x = vertexf[0];
nkeynes@319
   270
    unpacked[3].y = vertexf[1];
nkeynes@319
   271
    float t = ((unpacked[3].x - unpacked[1].x) * diff1.y -
nkeynes@319
   272
	       (unpacked[3].y - unpacked[1].y) * diff1.x) / detxy;
nkeynes@319
   273
    float s = ((unpacked[3].y - unpacked[1].y) * diff0.x -
nkeynes@319
   274
	       (unpacked[3].x - unpacked[1].x) * diff0.y) / detxy;
nkeynes@331
   275
    diff0.z = (1/unpacked[0].z) - (1/unpacked[1].z);
nkeynes@331
   276
    diff1.z = (1/unpacked[2].z) - (1/unpacked[1].z);
nkeynes@331
   277
    unpacked[3].z = 1/((1/unpacked[1].z) + (t*diff0.z) + (s*diff1.z));
nkeynes@319
   278
nkeynes@319
   279
    diff0.u = unpacked[0].u - unpacked[1].u;
nkeynes@319
   280
    diff0.v = unpacked[0].v - unpacked[1].v;
nkeynes@319
   281
    diff1.u = unpacked[2].u - unpacked[1].u;
nkeynes@319
   282
    diff1.v = unpacked[2].v - unpacked[1].v;
nkeynes@319
   283
    unpacked[3].u = unpacked[1].u + (t*diff0.u) + (s*diff1.u);
nkeynes@319
   284
    unpacked[3].v = unpacked[1].v + (t*diff0.v) + (s*diff1.v);
nkeynes@319
   285
nkeynes@319
   286
    if( !POLY1_GOURAUD_SHADED(poly1) ) {
nkeynes@319
   287
	memcpy( unpacked[3].rgba, unpacked[2].rgba, sizeof(unpacked[2].rgba) );
nkeynes@319
   288
	memcpy( unpacked[3].offset_rgba, unpacked[2].offset_rgba, sizeof(unpacked[2].offset_rgba) );
nkeynes@319
   289
    } else {
nkeynes@319
   290
	for( i=0; i<4; i++ ) {
nkeynes@319
   291
	    float d0 = unpacked[0].rgba[i] - unpacked[1].rgba[i];
nkeynes@319
   292
	    float d1 = unpacked[2].rgba[i] - unpacked[1].rgba[i];
nkeynes@319
   293
	    unpacked[3].rgba[i] = unpacked[1].rgba[i] + (t*d0) + (s*d1);
nkeynes@319
   294
	    d0 = unpacked[0].offset_rgba[i] - unpacked[1].offset_rgba[i];
nkeynes@319
   295
	    d1 = unpacked[2].offset_rgba[i] - unpacked[1].offset_rgba[i];
nkeynes@319
   296
	    unpacked[3].offset_rgba[i] = unpacked[1].offset_rgba[i] + (t*d0) + (s*d1);
nkeynes@319
   297
	}
nkeynes@319
   298
    }    
nkeynes@319
   299
}
nkeynes@319
   300
nkeynes@319
   301
void render_unpacked_vertex_array( uint32_t poly1, struct vertex_unpacked *vertexes[], 
nkeynes@319
   302
				   int num_vertexes ) {
nkeynes@319
   303
    int i;
nkeynes@319
   304
nkeynes@319
   305
    glBegin( GL_TRIANGLE_STRIP );
nkeynes@319
   306
nkeynes@319
   307
    for( i=0; i<num_vertexes; i++ ) {
nkeynes@319
   308
	if( POLY1_TEXTURED(poly1) ) {
nkeynes@319
   309
	    glTexCoord2f( vertexes[i]->u, vertexes[i]->v );
nkeynes@319
   310
	}
nkeynes@319
   311
nkeynes@322
   312
	if( pvr2_force_fragment_alpha ) {
nkeynes@322
   313
	    glColor4f( vertexes[i]->rgba[0], vertexes[i]->rgba[1], vertexes[i]->rgba[2], 1.0 );
nkeynes@322
   314
	} else {
nkeynes@322
   315
	    glColor4f( vertexes[i]->rgba[0], vertexes[i]->rgba[1], vertexes[i]->rgba[2],
nkeynes@322
   316
		       vertexes[i]->rgba[3] );
nkeynes@322
   317
	}
nkeynes@319
   318
	if( POLY1_SPECULAR(poly1) ) {
nkeynes@319
   319
	    glSecondaryColor3fEXT( vertexes[i]->offset_rgba[0],
nkeynes@319
   320
				   vertexes[i]->offset_rgba[1],
nkeynes@319
   321
				   vertexes[i]->offset_rgba[2] );
nkeynes@319
   322
	}
nkeynes@331
   323
	glVertex3f( vertexes[i]->x, vertexes[i]->y, 1/vertexes[i]->z );
nkeynes@319
   324
    }
nkeynes@319
   325
nkeynes@319
   326
    glEnd();
nkeynes@319
   327
}
nkeynes@319
   328
nkeynes@319
   329
void render_quad_vertexes( uint32_t poly1, uint32_t *vertexes, int vertex_size, int render_mode )
nkeynes@319
   330
{
nkeynes@319
   331
    struct vertex_unpacked unpacked[4];
nkeynes@319
   332
    struct vertex_unpacked *pt[4] = {&unpacked[0], &unpacked[1], &unpacked[3], &unpacked[2]};
nkeynes@319
   333
    render_unpack_quad( unpacked, poly1, vertexes, vertex_size, render_mode );
nkeynes@319
   334
    render_unpacked_vertex_array( poly1, pt, 4 );
nkeynes@319
   335
}
nkeynes@319
   336
nkeynes@319
   337
void render_vertex_array( uint32_t poly1, uint32_t *vert_array[], int num_vertexes, int vertex_size,
nkeynes@319
   338
			  int render_mode ) 
nkeynes@189
   339
{
nkeynes@189
   340
    int i, m=0;
nkeynes@189
   341
nkeynes@189
   342
    if( render_mode == RENDER_FULLMOD ) {
nkeynes@189
   343
	m = (vertex_size - 3)/2;
nkeynes@189
   344
    }
nkeynes@189
   345
nkeynes@189
   346
    glBegin( GL_TRIANGLE_STRIP );
nkeynes@189
   347
    
nkeynes@189
   348
    for( i=0; i<num_vertexes; i++ ) {
nkeynes@319
   349
	uint32_t *vertexes = vert_array[i];
nkeynes@319
   350
	float *vertexf = (float *)vert_array[i];
nkeynes@189
   351
	uint32_t argb;
nkeynes@318
   352
	int k = m + 3;
nkeynes@189
   353
	if( POLY1_TEXTURED(poly1) ) {
nkeynes@189
   354
	    if( POLY1_UV16(poly1) ) {
nkeynes@318
   355
		glTexCoord2f( halftofloat(vertexes[k]>>16),
nkeynes@318
   356
			      halftofloat(vertexes[k]) );
nkeynes@318
   357
		k++;
nkeynes@189
   358
	    } else {
nkeynes@318
   359
		glTexCoord2f( vertexf[k], vertexf[k+1] );
nkeynes@318
   360
		k+=2;
nkeynes@189
   361
	    }
nkeynes@189
   362
	}
nkeynes@189
   363
nkeynes@318
   364
	argb = vertexes[k++];
nkeynes@318
   365
	if( pvr2_force_fragment_alpha ) {
nkeynes@318
   366
	    glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8), 
nkeynes@318
   367
			(GLubyte)argb, 0xFF );
nkeynes@318
   368
	} else {
nkeynes@318
   369
	    glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8), 
nkeynes@318
   370
			(GLubyte)argb, (GLubyte)(argb >> 24) );
nkeynes@318
   371
	}
nkeynes@318
   372
nkeynes@318
   373
	if( POLY1_SPECULAR(poly1) ) {
nkeynes@318
   374
	    uint32_t spec = vertexes[k++];
nkeynes@318
   375
	    glSecondaryColor3ubEXT( (GLubyte)(spec >> 16), (GLubyte)(spec >> 8), 
nkeynes@318
   376
				 (GLubyte)spec );
nkeynes@318
   377
	}
nkeynes@331
   378
	glVertex3f( vertexf[0], vertexf[1], 1/vertexf[2] );
nkeynes@189
   379
	vertexes += vertex_size;
nkeynes@189
   380
    }
nkeynes@189
   381
nkeynes@189
   382
    glEnd();
nkeynes@189
   383
}
nkeynes@189
   384
nkeynes@319
   385
void render_vertexes( uint32_t poly1, uint32_t *vertexes, int num_vertexes, int vertex_size,
nkeynes@319
   386
		      int render_mode )
nkeynes@319
   387
{
nkeynes@319
   388
    uint32_t *vert_array[num_vertexes];
nkeynes@319
   389
    int i;
nkeynes@319
   390
    for( i=0; i<num_vertexes; i++ ) {
nkeynes@319
   391
	vert_array[i] = vertexes;
nkeynes@319
   392
	vertexes += vertex_size;
nkeynes@319
   393
    }
nkeynes@319
   394
    render_vertex_array( poly1, vert_array, num_vertexes, vertex_size, render_mode );
nkeynes@319
   395
}
nkeynes@319
   396
nkeynes@189
   397
/**
nkeynes@189
   398
 * Render a simple (not auto-sorted) tile
nkeynes@189
   399
 */
nkeynes@189
   400
void render_tile( pvraddr_t tile_entry, int render_mode, gboolean cheap_modifier_mode ) {
nkeynes@215
   401
    uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
nkeynes@189
   402
    uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
nkeynes@189
   403
    do {
nkeynes@189
   404
	uint32_t entry = *tile_list++;
nkeynes@189
   405
	if( entry >> 28 == 0x0F ) {
nkeynes@189
   406
	    break;
nkeynes@189
   407
	} else if( entry >> 28 == 0x0E ) {
nkeynes@189
   408
	    tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
nkeynes@189
   409
	} else {
nkeynes@215
   410
	    uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
nkeynes@189
   411
	    int is_modified = entry & 0x01000000;
nkeynes@189
   412
	    int vertex_length = (entry >> 21) & 0x07;
nkeynes@189
   413
	    int context_length = 3;
nkeynes@189
   414
	    if( is_modified && !cheap_modifier_mode ) {
nkeynes@189
   415
		context_length = 5;
nkeynes@189
   416
		vertex_length *= 2 ;
nkeynes@189
   417
	    }
nkeynes@189
   418
	    vertex_length += 3;
nkeynes@308
   419
	    
nkeynes@189
   420
	    if( (entry & 0xE0000000) == 0x80000000 ) {
nkeynes@189
   421
		/* Triangle(s) */
nkeynes@189
   422
		int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@189
   423
		int polygon_length = 3 * vertex_length + context_length;
nkeynes@189
   424
		int i;
nkeynes@189
   425
		for( i=0; i<strip_count; i++ ) {
nkeynes@189
   426
		    render_set_context( polygon, render_mode );
nkeynes@189
   427
		    render_vertexes( *polygon, polygon+context_length, 3, vertex_length,
nkeynes@477
   428
		    		     render_mode );
nkeynes@189
   429
		    polygon += polygon_length;
nkeynes@189
   430
		}
nkeynes@189
   431
	    } else if( (entry & 0xE0000000) == 0xA0000000 ) {
nkeynes@189
   432
		/* Sprite(s) */
nkeynes@319
   433
		int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@189
   434
		int polygon_length = 4 * vertex_length + context_length;
nkeynes@189
   435
		int i;
nkeynes@189
   436
		for( i=0; i<strip_count; i++ ) {
nkeynes@189
   437
		    render_set_context( polygon, render_mode );
nkeynes@319
   438
		    render_quad_vertexes( *polygon, polygon+context_length, vertex_length,
nkeynes@477
   439
		    			  render_mode );
nkeynes@189
   440
		    polygon += polygon_length;
nkeynes@189
   441
		}
nkeynes@189
   442
	    } else {
nkeynes@189
   443
		/* Polygon */
nkeynes@189
   444
		int i, first=-1, last = -1;
nkeynes@189
   445
		for( i=0; i<6; i++ ) {
nkeynes@189
   446
		    if( entry & (0x40000000>>i) ) {
nkeynes@189
   447
			if( first == -1 ) first = i;
nkeynes@189
   448
			last = i;
nkeynes@189
   449
		    }
nkeynes@189
   450
		}
nkeynes@189
   451
		if( first != -1 ) {
nkeynes@189
   452
		    first = 0;
nkeynes@189
   453
		    render_set_context(polygon, render_mode);
nkeynes@189
   454
		    render_vertexes( *polygon, polygon+context_length + (first*vertex_length),
nkeynes@477
   455
		    		     (last-first+3), vertex_length, render_mode );
nkeynes@189
   456
		}
nkeynes@189
   457
	    }
nkeynes@189
   458
	}
nkeynes@189
   459
    } while( 1 );
nkeynes@189
   460
}
nkeynes@189
   461
nkeynes@189
   462
void pvr2_render_tilebuffer( int width, int height, int clipx1, int clipy1, 
nkeynes@189
   463
			int clipx2, int clipy2 ) {
nkeynes@189
   464
nkeynes@191
   465
    pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
nkeynes@189
   466
    int tile_sort;
nkeynes@189
   467
    gboolean cheap_shadow;
nkeynes@189
   468
nkeynes@191
   469
    int obj_config = MMIO_READ( PVR2, RENDER_OBJCFG );
nkeynes@191
   470
    int isp_config = MMIO_READ( PVR2, RENDER_ISPCFG );
nkeynes@191
   471
    int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW );
nkeynes@189
   472
nkeynes@222
   473
    if( (obj_config & 0x00200000) == 0 ) {
nkeynes@189
   474
	if( isp_config & 1 ) {
nkeynes@189
   475
	    tile_sort = 0;
nkeynes@189
   476
	} else {
nkeynes@189
   477
	    tile_sort = 2;
nkeynes@189
   478
	}
nkeynes@189
   479
    } else {
nkeynes@189
   480
	tile_sort = 1;
nkeynes@189
   481
    }
nkeynes@189
   482
nkeynes@189
   483
    cheap_shadow = shadow_cfg & 0x100 ? TRUE : FALSE;
nkeynes@189
   484
nkeynes@189
   485
    struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
nkeynes@189
   486
nkeynes@189
   487
    glEnable( GL_SCISSOR_TEST );
nkeynes@268
   488
    do {
nkeynes@221
   489
	// fwrite_dump32v( (uint32_t *)segment, sizeof(struct tile_segment), 6, stderr );
nkeynes@189
   490
	int tilex = SEGMENT_X(segment->control);
nkeynes@189
   491
	int tiley = SEGMENT_Y(segment->control);
nkeynes@189
   492
	
nkeynes@189
   493
	int x1 = tilex << 5;
nkeynes@189
   494
	int y1 = tiley << 5;
nkeynes@189
   495
	if( x1 + 32 <= clipx1 ||
nkeynes@189
   496
	    y1 + 32 <= clipy1 ||
nkeynes@189
   497
	    x1 >= clipx2 ||
nkeynes@189
   498
	    y1 >= clipy2 ) {
nkeynes@189
   499
	    /* Tile completely clipped, skip */
nkeynes@189
   500
	    continue;
nkeynes@189
   501
	}
nkeynes@215
   502
nkeynes@189
   503
	/* Set a scissor on the visible part of the tile */
nkeynes@189
   504
	int w = MIN(x1+32, clipx2) - x1;
nkeynes@189
   505
	int h = MIN(y1+32, clipy2) - y1;
nkeynes@189
   506
	x1 = MAX(x1,clipx1);
nkeynes@189
   507
	y1 = MAX(y1,clipy1);
nkeynes@189
   508
	glScissor( x1, height-y1-h, w, h );
nkeynes@189
   509
nkeynes@189
   510
	if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
nkeynes@338
   511
	    if( pvr2_debug_render ) {
nkeynes@338
   512
		fprintf( stderr, "Tile %d,%d Opaque\n", tilex, tiley );
nkeynes@341
   513
		render_print_tilelist( stderr, segment->opaque_ptr );
nkeynes@338
   514
	    }
nkeynes@189
   515
	    if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
nkeynes@189
   516
		/* TODO */
nkeynes@189
   517
	    }
nkeynes@189
   518
	    render_tile( segment->opaque_ptr, RENDER_NORMAL, cheap_shadow );
nkeynes@189
   519
	}
nkeynes@189
   520
nkeynes@189
   521
	if( (segment->trans_ptr & NO_POINTER) == 0 ) {
nkeynes@338
   522
	    if( pvr2_debug_render ) {
nkeynes@338
   523
		fprintf( stderr, "Tile %d,%d Trans\n", tilex, tiley );
nkeynes@341
   524
		render_print_tilelist( stderr, segment->trans_ptr );
nkeynes@338
   525
	    }
nkeynes@189
   526
	    if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
nkeynes@189
   527
		/* TODO */
nkeynes@189
   528
	    } 
nkeynes@222
   529
	    if( tile_sort == 2 || 
nkeynes@222
   530
		(tile_sort == 1 && ((segment->control & SEGMENT_SORT_TRANS)==0)) ) {
nkeynes@189
   531
		render_autosort_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
nkeynes@189
   532
	    } else {
nkeynes@189
   533
		render_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow );
nkeynes@189
   534
	    }
nkeynes@189
   535
	}
nkeynes@189
   536
nkeynes@189
   537
	if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
nkeynes@338
   538
	    if( pvr2_debug_render ) {
nkeynes@338
   539
		fprintf( stderr, "Tile %d,%d Punchout\n", tilex, tiley );
nkeynes@341
   540
		render_print_tilelist( stderr, segment->punchout_ptr );
nkeynes@338
   541
	    }
nkeynes@189
   542
	    render_tile( segment->punchout_ptr, RENDER_NORMAL, cheap_shadow );
nkeynes@189
   543
	}
nkeynes@268
   544
    } while( ((segment++)->control & SEGMENT_END) == 0 );
nkeynes@189
   545
    glDisable( GL_SCISSOR_TEST );
nkeynes@189
   546
}
nkeynes@322
   547
nkeynes@322
   548
static float render_find_maximum_tile_z( pvraddr_t tile_entry, float inputz )
nkeynes@322
   549
{
nkeynes@322
   550
    uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
nkeynes@322
   551
    uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
nkeynes@322
   552
    int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100;
nkeynes@322
   553
    int i, j;
nkeynes@322
   554
    float z = inputz;
nkeynes@322
   555
    do {
nkeynes@322
   556
	uint32_t entry = *tile_list++;
nkeynes@322
   557
	if( entry >> 28 == 0x0F ) {
nkeynes@322
   558
	    break;
nkeynes@322
   559
	} else if( entry >> 28 == 0x0E ) {
nkeynes@322
   560
	    tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
nkeynes@322
   561
	} else {
nkeynes@322
   562
	    uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
nkeynes@322
   563
	    int vertex_length = (entry >> 21) & 0x07;
nkeynes@322
   564
	    int context_length = 3;
nkeynes@351
   565
	    if( (entry & 0x01000000) && (shadow_cfg==0) ) {
nkeynes@322
   566
		context_length = 5;
nkeynes@322
   567
		vertex_length *= 2 ;
nkeynes@322
   568
	    }
nkeynes@322
   569
	    vertex_length += 3;
nkeynes@322
   570
	    if( (entry & 0xE0000000) == 0x80000000 ) {
nkeynes@322
   571
		/* Triangle(s) */
nkeynes@322
   572
		int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@322
   573
		float *vertexz = (float *)(polygon+context_length+2);
nkeynes@322
   574
		for( i=0; i<strip_count; i++ ) {
nkeynes@322
   575
		    for( j=0; j<3; j++ ) {
nkeynes@322
   576
			if( *vertexz > z ) {
nkeynes@322
   577
			    z = *vertexz;
nkeynes@322
   578
			}
nkeynes@322
   579
			vertexz += vertex_length;
nkeynes@322
   580
		    }
nkeynes@322
   581
		    vertexz += context_length;
nkeynes@322
   582
		}
nkeynes@322
   583
	    } else if( (entry & 0xE0000000) == 0xA0000000 ) {
nkeynes@322
   584
		/* Sprite(s) */
nkeynes@322
   585
		int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@322
   586
		int i;
nkeynes@322
   587
		float *vertexz = (float *)(polygon+context_length+2);
nkeynes@322
   588
		for( i=0; i<strip_count; i++ ) {
nkeynes@322
   589
		    for( j=0; j<4; j++ ) {
nkeynes@322
   590
			if( *vertexz > z ) {
nkeynes@322
   591
			    z = *vertexz;
nkeynes@322
   592
			}
nkeynes@322
   593
			vertexz += vertex_length;
nkeynes@322
   594
		    }
nkeynes@322
   595
		    vertexz+=context_length;
nkeynes@322
   596
		}
nkeynes@322
   597
	    } else {
nkeynes@322
   598
		/* Polygon */
nkeynes@429
   599
		int i;
nkeynes@322
   600
		float *vertexz = (float *)polygon+context_length+2;
nkeynes@322
   601
		for( i=0; i<6; i++ ) {
nkeynes@322
   602
		    if( (entry & (0x40000000>>i)) && *vertexz > z ) {
nkeynes@322
   603
			z = *vertexz;
nkeynes@322
   604
		    }
nkeynes@322
   605
		    vertexz += vertex_length;
nkeynes@322
   606
		}
nkeynes@322
   607
	    }
nkeynes@322
   608
	}
nkeynes@322
   609
    } while(1);
nkeynes@322
   610
    return z;
nkeynes@322
   611
}
nkeynes@322
   612
nkeynes@322
   613
/**
nkeynes@322
   614
 * Scan through the scene to determine the largest z value (in order to set up
nkeynes@322
   615
 * an appropriate near clip plane).
nkeynes@322
   616
 */
nkeynes@322
   617
float pvr2_render_find_maximum_z( )
nkeynes@322
   618
{
nkeynes@322
   619
    pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
nkeynes@322
   620
    float maximumz = MMIO_READF( PVR2, RENDER_FARCLIP ); /* Initialize to the far clip plane */
nkeynes@322
   621
nkeynes@322
   622
    struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
nkeynes@322
   623
    do {
nkeynes@322
   624
	
nkeynes@322
   625
	if( (segment->opaque_ptr & NO_POINTER) == 0 ) {
nkeynes@322
   626
	    maximumz = render_find_maximum_tile_z(segment->opaque_ptr, maximumz);
nkeynes@322
   627
	}
nkeynes@322
   628
	if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) {
nkeynes@322
   629
	    maximumz = render_find_maximum_tile_z(segment->opaquemod_ptr, maximumz);
nkeynes@322
   630
	}
nkeynes@322
   631
	if( (segment->trans_ptr & NO_POINTER) == 0 ) {
nkeynes@322
   632
	    maximumz = render_find_maximum_tile_z(segment->trans_ptr, maximumz);
nkeynes@322
   633
	}
nkeynes@322
   634
	if( (segment->transmod_ptr & NO_POINTER) == 0 ) {
nkeynes@322
   635
	    maximumz = render_find_maximum_tile_z(segment->transmod_ptr, maximumz);
nkeynes@322
   636
	}
nkeynes@322
   637
	if( (segment->punchout_ptr & NO_POINTER) == 0 ) {
nkeynes@322
   638
	    maximumz = render_find_maximum_tile_z(segment->punchout_ptr, maximumz);
nkeynes@322
   639
	}
nkeynes@322
   640
nkeynes@322
   641
    } while( ((segment++)->control & SEGMENT_END) == 0 );
nkeynes@322
   642
nkeynes@331
   643
    return 1/maximumz;
nkeynes@322
   644
}
nkeynes@338
   645
nkeynes@338
   646
/**
nkeynes@338
   647
 * Scan the segment info to determine the width and height of the render (in 
nkeynes@338
   648
 * pixels).
nkeynes@338
   649
 * @param x,y output values to receive the width and height info.
nkeynes@338
   650
 */
nkeynes@338
   651
void pvr2_render_getsize( int *x, int *y ) 
nkeynes@338
   652
{
nkeynes@338
   653
    pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE );
nkeynes@338
   654
    int maxx = 0, maxy = 0;
nkeynes@338
   655
nkeynes@338
   656
    struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase);
nkeynes@338
   657
    do {
nkeynes@338
   658
	int tilex = SEGMENT_X(segment->control);
nkeynes@338
   659
	int tiley = SEGMENT_Y(segment->control);
nkeynes@338
   660
	if( tilex > maxx ) {
nkeynes@338
   661
	    maxx = tilex;
nkeynes@338
   662
	} 
nkeynes@338
   663
	if( tiley > maxy ) {
nkeynes@338
   664
	    maxy = tiley;
nkeynes@338
   665
	}
nkeynes@338
   666
    } while( ((segment++)->control & SEGMENT_END) == 0 );
nkeynes@338
   667
nkeynes@338
   668
    *x = (maxx+1)<<5;
nkeynes@338
   669
    *y = (maxy+1)<<5;
nkeynes@338
   670
}
nkeynes@341
   671
nkeynes@341
   672
void render_print_vertexes( FILE *f, uint32_t poly1, uint32_t *vert_array[], 
nkeynes@341
   673
			    int num_vertexes, int vertex_size )
nkeynes@341
   674
{
nkeynes@341
   675
    char buf[256], *p;
nkeynes@429
   676
    int i, k;
nkeynes@341
   677
    for( i=0; i<num_vertexes; i++ ) {
nkeynes@341
   678
	p = buf;
nkeynes@341
   679
	float *vertf = (float *)vert_array[i];
nkeynes@341
   680
	uint32_t *verti = (uint32_t *)vert_array[i];
nkeynes@341
   681
	p += sprintf( p, "  V %9.5f,%9.5f,%9.5f  ", vertf[0], vertf[1], vertf[2] );
nkeynes@341
   682
	k = 3;
nkeynes@341
   683
	if( POLY1_TEXTURED(poly1) ) {
nkeynes@341
   684
	    if( POLY1_UV16(poly1) ) {
nkeynes@341
   685
		p += sprintf( p, "uv=%9.5f,%9.5f  ",
nkeynes@341
   686
			       halftofloat(verti[k]>>16),
nkeynes@341
   687
			       halftofloat(verti[k]) );
nkeynes@341
   688
		k++;
nkeynes@341
   689
	    } else {
nkeynes@341
   690
		p += sprintf( p, "uv=%9.5f,%9.5f  ", vertf[k], vertf[k+1] );
nkeynes@341
   691
		k+=2;
nkeynes@341
   692
	    }
nkeynes@341
   693
	}
nkeynes@341
   694
nkeynes@341
   695
	p += sprintf( p, "%08X ", verti[k++] );
nkeynes@341
   696
	if( POLY1_SPECULAR(poly1) ) {
nkeynes@341
   697
	    p += sprintf( p, "%08X", verti[k++] );
nkeynes@341
   698
	}
nkeynes@341
   699
	p += sprintf( p, "\n" );
nkeynes@341
   700
	fprintf( f, buf );
nkeynes@341
   701
    }
nkeynes@341
   702
}
nkeynes@341
   703
nkeynes@341
   704
void render_print_polygon( FILE *f, uint32_t entry )
nkeynes@341
   705
{
nkeynes@341
   706
    uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE);
nkeynes@341
   707
    int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100;
nkeynes@429
   708
    int i;
nkeynes@341
   709
nkeynes@341
   710
    if( entry >> 28 == 0x0F ) {
nkeynes@341
   711
	fprintf( f, "EOT\n" );
nkeynes@341
   712
    } else if( entry >> 28 == 0x0E ) {
nkeynes@341
   713
	fprintf( f, "LINK %08X\n", entry &0x7FFFFF );
nkeynes@341
   714
    } else {
nkeynes@341
   715
	uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2));
nkeynes@341
   716
	int vertex_length = (entry >> 21) & 0x07;
nkeynes@341
   717
	int context_length = 3;
nkeynes@351
   718
	if( (entry & 0x01000000) && (shadow_cfg==0) ) {
nkeynes@341
   719
	    context_length = 5;
nkeynes@341
   720
	    vertex_length *= 2 ;
nkeynes@341
   721
	}
nkeynes@341
   722
	vertex_length += 3;
nkeynes@341
   723
	if( (entry & 0xE0000000) == 0x80000000 ) {
nkeynes@341
   724
	    /* Triangle(s) */
nkeynes@341
   725
	    int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@341
   726
	    for( i=0; i<strip_count; i++ ) {
nkeynes@341
   727
		fprintf( f, "TRI  %08X %08X %08X\n", polygon[0], polygon[1], polygon[2] ); 
nkeynes@341
   728
		uint32_t *array[3];
nkeynes@341
   729
		array[0] = polygon + context_length;
nkeynes@341
   730
		array[1] = array[0] + vertex_length;
nkeynes@341
   731
		array[2] = array[1] + vertex_length;
nkeynes@341
   732
		render_print_vertexes( f, *polygon, array, 3, vertex_length );
nkeynes@341
   733
		polygon = array[2] + vertex_length;
nkeynes@341
   734
	    }
nkeynes@341
   735
	} else if( (entry & 0xE0000000) == 0xA0000000 ) {
nkeynes@341
   736
	    /* Sprite(s) */
nkeynes@341
   737
	    int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@341
   738
	    for( i=0; i<strip_count; i++ ) {
nkeynes@341
   739
		fprintf( f, "QUAD %08X %08X %08X\n", polygon[0], polygon[1], polygon[2] ); 
nkeynes@341
   740
		uint32_t *array[4];
nkeynes@341
   741
		array[0] = polygon + context_length;
nkeynes@341
   742
		array[1] = array[0] + vertex_length;
nkeynes@341
   743
		array[2] = array[1] + vertex_length;
nkeynes@341
   744
		array[3] = array[2] + vertex_length;
nkeynes@341
   745
		render_print_vertexes( f, *polygon, array, 4, vertex_length );
nkeynes@341
   746
		polygon = array[3] + vertex_length;
nkeynes@341
   747
	    }
nkeynes@341
   748
	} else {
nkeynes@341
   749
	    /* Polygon */
nkeynes@341
   750
	    int last = -1;
nkeynes@341
   751
	    uint32_t *array[8];
nkeynes@341
   752
	    for( i=0; i<6; i++ ) {
nkeynes@341
   753
		if( entry & (0x40000000>>i) ) {
nkeynes@341
   754
		    last = i;
nkeynes@341
   755
		}
nkeynes@341
   756
	    }
nkeynes@341
   757
	    fprintf( f, "POLY %08X %08X %08X\n", polygon[0], polygon[1], polygon[2] );
nkeynes@341
   758
	    for( i=0; i<last+2; i++ ) {
nkeynes@341
   759
		array[i] = polygon + context_length + vertex_length*i;
nkeynes@341
   760
	    }
nkeynes@341
   761
	    render_print_vertexes( f, *polygon, array, last+2, vertex_length );
nkeynes@341
   762
	}
nkeynes@341
   763
    }
nkeynes@341
   764
}
nkeynes@341
   765
nkeynes@341
   766
void render_print_tilelist( FILE *f, uint32_t tile_entry )
nkeynes@341
   767
{
nkeynes@341
   768
    uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
nkeynes@341
   769
    do {
nkeynes@341
   770
	uint32_t entry = *tile_list++;
nkeynes@341
   771
	if( entry >> 28 == 0x0F ) {
nkeynes@341
   772
	    break;
nkeynes@341
   773
	} else if( entry >> 28 == 0x0E ) {
nkeynes@341
   774
	    tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
nkeynes@341
   775
	} else {
nkeynes@341
   776
	    render_print_polygon(f, entry);
nkeynes@341
   777
	}
nkeynes@341
   778
    } while( 1 );
nkeynes@341
   779
}
nkeynes@341
   780
.