Search
lxdream.org :: lxdream/src/pvr2/scene.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/scene.c
changeset 677:3ee62740ff8f
prev669:ab344e42bca9
next687:6bdc2b7032ea
author nkeynes
date Thu May 29 10:50:25 2008 +0000 (13 years ago)
permissions -rw-r--r--
last change Remove pvr2mmio.h include from pvr2.h (it's supposed to be moore or less private)
Move redraw function from driver into pvr2_redraw_display()
file annotate diff log raw
nkeynes@653
     1
/**
nkeynes@653
     2
 * $Id$
nkeynes@653
     3
 *
nkeynes@653
     4
 * Manage the internal vertex/polygon buffers and scene data structure. 
nkeynes@653
     5
 * Where possible this uses VBOs for the vertex + index data.
nkeynes@653
     6
 *
nkeynes@653
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@653
     8
 *
nkeynes@653
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@653
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@653
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@653
    12
 * (at your option) any later version.
nkeynes@653
    13
 *
nkeynes@653
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@653
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@653
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@653
    17
 * GNU General Public License for more details.
nkeynes@653
    18
 */
nkeynes@653
    19
nkeynes@653
    20
#include <assert.h>
nkeynes@653
    21
#include <string.h>
nkeynes@653
    22
#include <math.h>
nkeynes@653
    23
#include "lxdream.h"
nkeynes@653
    24
#include "display.h"
nkeynes@653
    25
#include "pvr2/pvr2.h"
nkeynes@677
    26
#include "pvr2/pvr2mmio.h"
nkeynes@653
    27
#include "pvr2/glutil.h"
nkeynes@653
    28
#include "pvr2/scene.h"
nkeynes@653
    29
nkeynes@653
    30
nkeynes@653
    31
static inline uint32_t bgra_to_rgba(uint32_t bgra)
nkeynes@653
    32
{
nkeynes@653
    33
    return (bgra&0xFF00FF00) | ((bgra&0x00FF0000)>>16) | ((bgra&0x000000FF)<<16);
nkeynes@653
    34
}
nkeynes@653
    35
nkeynes@653
    36
/**
nkeynes@653
    37
 * Convert a half-float (16-bit) FP number to a regular 32-bit float.
nkeynes@653
    38
 * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa.
nkeynes@653
    39
 * TODO: Check the correctness of this.
nkeynes@653
    40
 */
nkeynes@653
    41
static float halftofloat( uint16_t half )
nkeynes@653
    42
{
nkeynes@653
    43
    union {
nkeynes@653
    44
        float f;
nkeynes@653
    45
        uint32_t i;
nkeynes@653
    46
    } temp;
nkeynes@653
    47
    temp.i = ((uint32_t)half)<<16;
nkeynes@653
    48
    return temp.f;
nkeynes@653
    49
}
nkeynes@653
    50
nkeynes@653
    51
nkeynes@653
    52
nkeynes@653
    53
nkeynes@653
    54
nkeynes@653
    55
struct pvr2_scene_struct pvr2_scene;
nkeynes@653
    56
nkeynes@653
    57
static gboolean vbo_init = FALSE;
nkeynes@669
    58
nkeynes@669
    59
#ifdef ENABLE_VERTEX_BUFFER
nkeynes@653
    60
static gboolean vbo_supported = FALSE;
nkeynes@669
    61
#endif
nkeynes@653
    62
nkeynes@653
    63
/**
nkeynes@653
    64
 * Test for VBO support, and allocate all the system memory needed for the
nkeynes@653
    65
 * temporary structures. GL context must have been initialized before this
nkeynes@653
    66
 * point.
nkeynes@653
    67
 */
nkeynes@653
    68
void pvr2_scene_init()
nkeynes@653
    69
{
nkeynes@653
    70
    if( !vbo_init ) {
nkeynes@653
    71
#ifdef ENABLE_VERTEX_BUFFER
nkeynes@667
    72
	if( isGLVertexBufferSupported() ) {
nkeynes@653
    73
	    vbo_supported = TRUE;
nkeynes@653
    74
	    pvr2_scene.vbo_id = 1;
nkeynes@653
    75
	}
nkeynes@653
    76
#endif
nkeynes@653
    77
	pvr2_scene.vertex_array = NULL;
nkeynes@653
    78
	pvr2_scene.vertex_array_size = 0;
nkeynes@653
    79
	pvr2_scene.poly_array = g_malloc( MAX_POLY_BUFFER_SIZE );
nkeynes@653
    80
	pvr2_scene.buf_to_poly_map = g_malloc0( BUF_POLY_MAP_SIZE );
nkeynes@653
    81
	vbo_init = TRUE;
nkeynes@653
    82
    }
nkeynes@653
    83
}
nkeynes@653
    84
nkeynes@653
    85
/**
nkeynes@653
    86
 * Clear the scene data structures in preparation for fresh data
nkeynes@653
    87
 */
nkeynes@653
    88
void pvr2_scene_reset()
nkeynes@653
    89
{
nkeynes@653
    90
    pvr2_scene.poly_count = 0;
nkeynes@653
    91
    pvr2_scene.vertex_count = 0;
nkeynes@653
    92
    memset( pvr2_scene.buf_to_poly_map, 0, BUF_POLY_MAP_SIZE );
nkeynes@653
    93
}
nkeynes@653
    94
nkeynes@653
    95
void pvr2_scene_shutdown()
nkeynes@653
    96
{
nkeynes@653
    97
#ifdef ENABLE_VERTEX_BUFFER
nkeynes@653
    98
    if( vbo_supported ) {
nkeynes@653
    99
	glBindBufferARB( GL_ARRAY_BUFFER_ARB, 0 );
nkeynes@653
   100
	glDeleteBuffersARB( 1, &pvr2_scene.vbo_id );
nkeynes@653
   101
	pvr2_scene.vbo_id = 0;
nkeynes@653
   102
    } else {
nkeynes@653
   103
#endif
nkeynes@653
   104
	g_free( pvr2_scene.vertex_array );
nkeynes@653
   105
	pvr2_scene.vertex_array = NULL;
nkeynes@653
   106
#ifdef ENABLE_VERTEX_BUFFER
nkeynes@653
   107
    }
nkeynes@653
   108
#endif
nkeynes@653
   109
nkeynes@653
   110
    g_free( pvr2_scene.poly_array );
nkeynes@653
   111
    pvr2_scene.poly_array = NULL;
nkeynes@653
   112
    g_free( pvr2_scene.buf_to_poly_map );
nkeynes@653
   113
    pvr2_scene.buf_to_poly_map = NULL;
nkeynes@653
   114
    vbo_init = FALSE;
nkeynes@653
   115
}
nkeynes@653
   116
nkeynes@653
   117
void *vertex_buffer_map()
nkeynes@653
   118
{
nkeynes@653
   119
    glGetError();
nkeynes@653
   120
    uint32_t size = pvr2_scene.vertex_count * sizeof(struct vertex_struct);
nkeynes@653
   121
#ifdef ENABLE_VERTEX_BUFFER
nkeynes@653
   122
    if( vbo_supported ) {
nkeynes@653
   123
	glBindBufferARB( GL_ARRAY_BUFFER_ARB, pvr2_scene.vbo_id );
nkeynes@653
   124
	if( size > pvr2_scene.vertex_array_size ) {
nkeynes@653
   125
	    glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, NULL, GL_DYNAMIC_DRAW_ARB );
nkeynes@653
   126
	    int status = glGetError();
nkeynes@653
   127
	    if( status != 0 ) {
nkeynes@653
   128
		fprintf( stderr, "Error %08X allocating vertex buffer\n", status );
nkeynes@653
   129
		abort();
nkeynes@653
   130
	    }
nkeynes@653
   131
	    pvr2_scene.vertex_array_size = size;
nkeynes@653
   132
	}
nkeynes@653
   133
	pvr2_scene.vertex_array = glMapBufferARB( GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB );
nkeynes@653
   134
	assert(pvr2_scene.vertex_array != NULL );
nkeynes@653
   135
    } else {
nkeynes@653
   136
#endif
nkeynes@653
   137
	if( size > pvr2_scene.vertex_array_size ) {
nkeynes@653
   138
	    pvr2_scene.vertex_array = g_realloc( pvr2_scene.vertex_array, size );
nkeynes@653
   139
	}
nkeynes@653
   140
#ifdef ENABLE_VERTEX_BUFFER
nkeynes@653
   141
    }
nkeynes@653
   142
#endif
nkeynes@653
   143
    return pvr2_scene.vertex_array;
nkeynes@653
   144
}
nkeynes@653
   145
nkeynes@653
   146
gboolean vertex_buffer_unmap()
nkeynes@653
   147
{
nkeynes@653
   148
#ifdef ENABLE_VERTEX_BUFFER
nkeynes@653
   149
    if( vbo_supported ) {
nkeynes@653
   150
	pvr2_scene.vertex_array = NULL;
nkeynes@653
   151
	return glUnmapBufferARB( GL_ARRAY_BUFFER_ARB );
nkeynes@653
   152
    } else {
nkeynes@653
   153
	return TRUE;
nkeynes@653
   154
    }
nkeynes@653
   155
#else
nkeynes@653
   156
    return TRUE;
nkeynes@653
   157
#endif
nkeynes@653
   158
}
nkeynes@653
   159
nkeynes@653
   160
static struct polygon_struct *scene_add_polygon( pvraddr_t poly_idx, int vertex_count,
nkeynes@653
   161
							 gboolean is_modified ) 
nkeynes@653
   162
{
nkeynes@653
   163
    int vert_mul = is_modified ? 2 : 1;
nkeynes@653
   164
nkeynes@653
   165
    if( pvr2_scene.buf_to_poly_map[poly_idx] != NULL ) {
nkeynes@653
   166
	if( vertex_count > pvr2_scene.buf_to_poly_map[poly_idx]->vertex_count ) {
nkeynes@653
   167
	    pvr2_scene.vertex_count += (vertex_count - pvr2_scene.buf_to_poly_map[poly_idx]->vertex_count) * vert_mul;
nkeynes@653
   168
	    pvr2_scene.buf_to_poly_map[poly_idx]->vertex_count = vertex_count;
nkeynes@653
   169
	}
nkeynes@653
   170
	return pvr2_scene.buf_to_poly_map[poly_idx];
nkeynes@653
   171
    } else {
nkeynes@653
   172
	struct polygon_struct *poly = &pvr2_scene.poly_array[pvr2_scene.poly_count++];
nkeynes@653
   173
	poly->context = (uint32_t *)(video_base + MMIO_READ(PVR2,RENDER_POLYBASE) + (poly_idx<<2));
nkeynes@653
   174
	poly->vertex_count = vertex_count;
nkeynes@653
   175
	poly->vertex_index = -1;
nkeynes@653
   176
	poly->mod_vertex_index = -1;
nkeynes@653
   177
	poly->next = NULL;
nkeynes@653
   178
	pvr2_scene.buf_to_poly_map[poly_idx] = poly;
nkeynes@653
   179
	pvr2_scene.vertex_count += (vertex_count * vert_mul);
nkeynes@653
   180
	return poly;
nkeynes@653
   181
    }
nkeynes@653
   182
}
nkeynes@653
   183
nkeynes@653
   184
/**
nkeynes@653
   185
 * Decode a single PVR2 renderable vertex (opaque/trans/punch-out, but not shadow
nkeynes@653
   186
 * volume)
nkeynes@653
   187
 * @param vert Pointer to output vertex structure
nkeynes@653
   188
 * @param poly1 First word of polygon context (needed to understand vertex)
nkeynes@653
   189
 * @param poly2 Second word of polygon context
nkeynes@653
   190
 * @param pvr2_data Pointer to raw pvr2 vertex data (in VRAM)
nkeynes@653
   191
 * @param modify_offset Offset in 32-bit words to the tex/color data. 0 for
nkeynes@653
   192
 *        the normal vertex, half the vertex length for the modified vertex.
nkeynes@653
   193
 */
nkeynes@653
   194
static void pvr2_decode_render_vertex( struct vertex_struct *vert, uint32_t poly1, 
nkeynes@653
   195
				       uint32_t poly2, uint32_t *pvr2_data, 
nkeynes@653
   196
				       int modify_offset )
nkeynes@653
   197
{
nkeynes@653
   198
    gboolean force_alpha = !POLY2_ALPHA_ENABLE(poly2);
nkeynes@653
   199
    union pvr2_data_type {
nkeynes@653
   200
	uint32_t *ival;
nkeynes@653
   201
	float *fval;
nkeynes@653
   202
    } data;
nkeynes@653
   203
nkeynes@653
   204
    data.ival = pvr2_data;
nkeynes@653
   205
    
nkeynes@653
   206
    vert->x = *data.fval++;
nkeynes@653
   207
    vert->y = *data.fval++;
nkeynes@653
   208
nkeynes@653
   209
    float z = *data.fval++;
nkeynes@653
   210
    if( !isfinite(z) ) {
nkeynes@653
   211
	z = 0;
nkeynes@653
   212
    } else if( z != 0 ) {
nkeynes@653
   213
	z = 1/z;
nkeynes@653
   214
    }
nkeynes@653
   215
    if( z > pvr2_scene.bounds[5] ) {
nkeynes@653
   216
	pvr2_scene.bounds[5] = z;
nkeynes@653
   217
    } else if( z < pvr2_scene.bounds[4] && z != 0 ) {
nkeynes@653
   218
	pvr2_scene.bounds[4] = z;
nkeynes@653
   219
    }
nkeynes@653
   220
    vert->z = z;
nkeynes@653
   221
    data.ival += modify_offset;
nkeynes@653
   222
nkeynes@653
   223
    
nkeynes@653
   224
    if( POLY1_TEXTURED(poly1) ) {
nkeynes@653
   225
	if( POLY1_UV16(poly1) ) {
nkeynes@653
   226
	    vert->u = halftofloat( *data.ival>>16 );
nkeynes@653
   227
	    vert->v = halftofloat( *data.ival );
nkeynes@653
   228
	    data.ival++;
nkeynes@653
   229
	} else {
nkeynes@653
   230
	    vert->u = *data.fval++;
nkeynes@653
   231
	    vert->v = *data.fval++;
nkeynes@653
   232
	}
nkeynes@653
   233
	if( POLY2_TEX_BLEND(poly2) == 1 ) {
nkeynes@653
   234
	    force_alpha = TRUE;
nkeynes@653
   235
	}
nkeynes@653
   236
    }
nkeynes@653
   237
    if( force_alpha ) {
nkeynes@653
   238
	vert->rgba = bgra_to_rgba((*data.ival++) | 0xFF000000);
nkeynes@653
   239
	if( POLY1_SPECULAR(poly1) ) {
nkeynes@653
   240
	    vert->offset_rgba = bgra_to_rgba((*data.ival++) | 0xFF000000);
nkeynes@653
   241
	} else {
nkeynes@653
   242
	    vert->offset_rgba = 0;
nkeynes@653
   243
	}
nkeynes@653
   244
    } else {
nkeynes@653
   245
	vert->rgba = bgra_to_rgba(*data.ival++);
nkeynes@653
   246
	if( POLY1_SPECULAR(poly1) ) {
nkeynes@653
   247
	    vert->offset_rgba = bgra_to_rgba(*data.ival++);
nkeynes@653
   248
	} else {
nkeynes@653
   249
	    vert->offset_rgba = 0;
nkeynes@653
   250
	}
nkeynes@653
   251
    }
nkeynes@653
   252
}
nkeynes@653
   253
nkeynes@653
   254
/**
nkeynes@653
   255
 * Compute texture, colour, and z values for a result point by interpolating from
nkeynes@653
   256
 * a set of 3 input points. The result point must define its x,y.
nkeynes@653
   257
 */
nkeynes@653
   258
static void scene_compute_vertex( struct vertex_struct *result, 
nkeynes@653
   259
					  struct vertex_struct *input,
nkeynes@653
   260
					  gboolean is_solid_shaded )
nkeynes@653
   261
{
nkeynes@653
   262
    int i;
nkeynes@653
   263
    float sx = input[2].x - input[1].x;
nkeynes@653
   264
    float sy = input[2].y - input[1].y;
nkeynes@653
   265
    float tx = input[0].x - input[1].x;
nkeynes@653
   266
    float ty = input[0].y - input[1].y;
nkeynes@653
   267
nkeynes@653
   268
    float detxy = ((sy) * (tx)) - ((ty) * (sx));
nkeynes@653
   269
    if( detxy == 0 ) {
nkeynes@653
   270
	result->z = input[2].z;
nkeynes@653
   271
	result->u = input[2].u;
nkeynes@653
   272
	result->v = input[2].v;
nkeynes@653
   273
	result->rgba = input[2].rgba;
nkeynes@653
   274
	result->offset_rgba = input[2].offset_rgba;
nkeynes@653
   275
	return;
nkeynes@653
   276
    }
nkeynes@653
   277
    float t = ((result->x - input[1].x) * sy -
nkeynes@653
   278
	       (result->y - input[1].y) * sx) / detxy;
nkeynes@653
   279
    float s = ((result->y - input[1].y) * tx -
nkeynes@653
   280
	       (result->x - input[1].x) * ty) / detxy;
nkeynes@653
   281
nkeynes@653
   282
    float sz = input[2].z - input[1].z;
nkeynes@653
   283
    float tz = input[0].z - input[1].z;
nkeynes@653
   284
    float su = input[2].u - input[1].u;
nkeynes@653
   285
    float tu = input[0].u - input[1].u;
nkeynes@653
   286
    float sv = input[2].v - input[1].v;
nkeynes@653
   287
    float tv = input[0].v - input[1].v;
nkeynes@653
   288
nkeynes@653
   289
    float rz = input[1].z + (t*tz) + (s*sz);
nkeynes@653
   290
    if( rz > pvr2_scene.bounds[5] ) {
nkeynes@653
   291
	pvr2_scene.bounds[5] = rz;
nkeynes@653
   292
    } else if( rz < pvr2_scene.bounds[4] ) {
nkeynes@653
   293
	pvr2_scene.bounds[4] = rz; 
nkeynes@653
   294
    }
nkeynes@653
   295
    result->z = rz;
nkeynes@653
   296
    result->u = input[1].u + (t*tu) + (s*su);
nkeynes@653
   297
    result->v = input[1].v + (t*tv) + (s*sv);
nkeynes@653
   298
nkeynes@653
   299
    if( is_solid_shaded ) {
nkeynes@653
   300
	result->rgba = input[2].rgba;
nkeynes@653
   301
	result->offset_rgba = input[2].offset_rgba;
nkeynes@653
   302
    } else {
nkeynes@653
   303
	uint8_t *rgba0 = (uint8_t *)&input[0].rgba;
nkeynes@653
   304
	uint8_t *rgba1 = (uint8_t *)&input[1].rgba;
nkeynes@653
   305
	uint8_t *rgba2 = (uint8_t *)&input[2].rgba;
nkeynes@653
   306
	uint8_t *rgba3 = (uint8_t *)&result->rgba;
nkeynes@653
   307
	for( i=0; i<8; i++ ) { // note: depends on rgba & offset_rgba being adjacent
nkeynes@653
   308
	    float tc = *rgba0++ - *rgba1;
nkeynes@653
   309
	    float sc = *rgba2++ - *rgba1;
nkeynes@653
   310
	    float rc = *rgba1++ + (t*tc) + (s*sc);
nkeynes@653
   311
	    if( rc < 0 ) {
nkeynes@653
   312
		rc = 0;
nkeynes@653
   313
	    } else if( rc > 255 ) {
nkeynes@653
   314
		rc = 255;
nkeynes@653
   315
	    }
nkeynes@653
   316
	    *rgba3++ = rc;
nkeynes@653
   317
	}
nkeynes@653
   318
    }    
nkeynes@653
   319
nkeynes@653
   320
}
nkeynes@653
   321
nkeynes@653
   322
static void scene_add_vertexes( pvraddr_t poly_idx, int vertex_length,
nkeynes@653
   323
					gboolean is_modified )
nkeynes@653
   324
{
nkeynes@653
   325
    struct polygon_struct *poly = pvr2_scene.buf_to_poly_map[poly_idx];
nkeynes@653
   326
    uint32_t *ptr = &pvr2_scene.pvr2_pbuf[poly_idx];
nkeynes@653
   327
    uint32_t *context = ptr;
nkeynes@653
   328
    unsigned int i;
nkeynes@653
   329
nkeynes@653
   330
    if( poly->vertex_index == -1 ) {
nkeynes@653
   331
	ptr += (is_modified ? 5 : 3 );
nkeynes@653
   332
	poly->vertex_index = pvr2_scene.vertex_index;
nkeynes@653
   333
	
nkeynes@653
   334
	assert( poly != NULL );
nkeynes@653
   335
	assert( pvr2_scene.vertex_index + poly->vertex_count <= pvr2_scene.vertex_count );
nkeynes@653
   336
	for( i=0; i<poly->vertex_count; i++ ) {
nkeynes@653
   337
	    pvr2_decode_render_vertex( &pvr2_scene.vertex_array[pvr2_scene.vertex_index++], context[0], context[1], ptr, 0 );
nkeynes@653
   338
	    ptr += vertex_length;
nkeynes@653
   339
	}
nkeynes@653
   340
	if( is_modified ) {
nkeynes@653
   341
	    int mod_offset = (vertex_length - 3)>>1;
nkeynes@653
   342
	    assert( pvr2_scene.vertex_index + poly->vertex_count <= pvr2_scene.vertex_count );
nkeynes@653
   343
	    ptr = &pvr2_scene.pvr2_pbuf[poly_idx] + 5;
nkeynes@653
   344
	    poly->mod_vertex_index = pvr2_scene.vertex_index;
nkeynes@653
   345
	    for( i=0; i<poly->vertex_count; i++ ) {
nkeynes@653
   346
		pvr2_decode_render_vertex( &pvr2_scene.vertex_array[pvr2_scene.vertex_index++], context[0], context[3], ptr, mod_offset );
nkeynes@653
   347
		ptr += vertex_length;
nkeynes@653
   348
	    }
nkeynes@653
   349
	}
nkeynes@653
   350
    }
nkeynes@653
   351
}
nkeynes@653
   352
nkeynes@653
   353
static void scene_add_quad_vertexes( pvraddr_t poly_idx, int vertex_length, 
nkeynes@653
   354
					     gboolean is_modified )
nkeynes@653
   355
{
nkeynes@653
   356
    struct polygon_struct *poly = pvr2_scene.buf_to_poly_map[poly_idx];
nkeynes@653
   357
    uint32_t *ptr = &pvr2_scene.pvr2_pbuf[poly_idx];
nkeynes@653
   358
    uint32_t *context = ptr;
nkeynes@653
   359
    unsigned int i;
nkeynes@653
   360
nkeynes@653
   361
    if( poly->vertex_index == -1 ) {
nkeynes@653
   362
	// Construct it locally and copy to the vertex buffer, as the VBO is 
nkeynes@653
   363
	// allowed to be horribly slow for reads (ie it could be direct-mapped
nkeynes@653
   364
	// vram).
nkeynes@653
   365
	struct vertex_struct quad[4];
nkeynes@653
   366
	
nkeynes@653
   367
	assert( poly != NULL );
nkeynes@653
   368
	assert( pvr2_scene.vertex_index + poly->vertex_count <= pvr2_scene.vertex_count );
nkeynes@653
   369
	ptr += (is_modified ? 5 : 3 );
nkeynes@653
   370
	poly->vertex_index = pvr2_scene.vertex_index;
nkeynes@653
   371
	for( i=0; i<4; i++ ) {
nkeynes@653
   372
	    pvr2_decode_render_vertex( &quad[i], context[0], context[1], ptr, 0 );
nkeynes@653
   373
	    ptr += vertex_length;
nkeynes@653
   374
	}
nkeynes@653
   375
	scene_compute_vertex( &quad[3], &quad[0], !POLY1_GOURAUD_SHADED(context[0]) );
nkeynes@653
   376
	// Swap last two vertexes (quad arrangement => tri strip arrangement)
nkeynes@653
   377
	memcpy( &pvr2_scene.vertex_array[pvr2_scene.vertex_index], quad, sizeof(struct vertex_struct)*2 );
nkeynes@653
   378
	memcpy( &pvr2_scene.vertex_array[pvr2_scene.vertex_index+2], &quad[3], sizeof(struct vertex_struct) );
nkeynes@653
   379
	memcpy( &pvr2_scene.vertex_array[pvr2_scene.vertex_index+3], &quad[2], sizeof(struct vertex_struct) );
nkeynes@653
   380
	pvr2_scene.vertex_index += 4;
nkeynes@653
   381
	
nkeynes@653
   382
	if( is_modified ) {
nkeynes@653
   383
	    int mod_offset = (vertex_length - 3)>>1;
nkeynes@653
   384
	    assert( pvr2_scene.vertex_index + poly->vertex_count <= pvr2_scene.vertex_count );
nkeynes@653
   385
	    ptr = &pvr2_scene.pvr2_pbuf[poly_idx] + 5;
nkeynes@653
   386
	    poly->mod_vertex_index = pvr2_scene.vertex_index;
nkeynes@653
   387
	    for( i=0; i<4; i++ ) {
nkeynes@653
   388
		pvr2_decode_render_vertex( &quad[4], context[0], context[3], ptr, mod_offset );
nkeynes@653
   389
		ptr += vertex_length;
nkeynes@653
   390
	    }
nkeynes@653
   391
	    scene_compute_vertex( &quad[3], &quad[0], !POLY1_GOURAUD_SHADED(context[0]) );
nkeynes@653
   392
	    memcpy( &pvr2_scene.vertex_array[pvr2_scene.vertex_index], quad, sizeof(struct vertex_struct)*2 );
nkeynes@653
   393
	    memcpy( &pvr2_scene.vertex_array[pvr2_scene.vertex_index+2], &quad[3], sizeof(struct vertex_struct) );
nkeynes@653
   394
	    memcpy( &pvr2_scene.vertex_array[pvr2_scene.vertex_index+3], &quad[2], sizeof(struct vertex_struct) );
nkeynes@653
   395
	    pvr2_scene.vertex_index += 4;
nkeynes@653
   396
	}
nkeynes@653
   397
    }
nkeynes@653
   398
}
nkeynes@653
   399
nkeynes@653
   400
static void scene_extract_polygons( pvraddr_t tile_entry )
nkeynes@653
   401
{
nkeynes@653
   402
    uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
nkeynes@653
   403
    do {
nkeynes@653
   404
	uint32_t entry = *tile_list++;
nkeynes@653
   405
	if( entry >> 28 == 0x0F ) {
nkeynes@653
   406
	    break;
nkeynes@653
   407
	} else if( entry >> 28 == 0x0E ) {
nkeynes@653
   408
	    tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
nkeynes@653
   409
	} else {
nkeynes@653
   410
	    pvraddr_t polyaddr = entry&0x000FFFFF;
nkeynes@653
   411
	    int is_modified = (entry & 0x01000000) && pvr2_scene.full_shadow;
nkeynes@653
   412
	    int vertex_length = (entry >> 21) & 0x07;
nkeynes@653
   413
	    int context_length = 3;
nkeynes@653
   414
	    if( is_modified ) {
nkeynes@653
   415
		context_length = 5;
nkeynes@653
   416
		vertex_length <<= 1 ;
nkeynes@653
   417
	    }
nkeynes@653
   418
	    vertex_length += 3;
nkeynes@653
   419
	    
nkeynes@653
   420
	    if( (entry & 0xE0000000) == 0x80000000 ) {
nkeynes@653
   421
		/* Triangle(s) */
nkeynes@653
   422
		int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@653
   423
		int polygon_length = 3 * vertex_length + context_length;
nkeynes@653
   424
		int i;
nkeynes@653
   425
		struct polygon_struct *last_poly = NULL;
nkeynes@653
   426
		for( i=0; i<strip_count; i++ ) {
nkeynes@653
   427
		    struct polygon_struct *poly = scene_add_polygon( polyaddr, 3, is_modified );
nkeynes@653
   428
		    polyaddr += polygon_length;
nkeynes@653
   429
		    if( last_poly != NULL && last_poly->next == NULL ) {
nkeynes@653
   430
			last_poly->next = poly;
nkeynes@653
   431
		    }
nkeynes@653
   432
		    last_poly = poly;
nkeynes@653
   433
		}
nkeynes@653
   434
	    } else if( (entry & 0xE0000000) == 0xA0000000 ) {
nkeynes@653
   435
		/* Sprite(s) */
nkeynes@653
   436
		int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@653
   437
		int polygon_length = 4 * vertex_length + context_length;
nkeynes@653
   438
		int i;
nkeynes@653
   439
		struct polygon_struct *last_poly = NULL;
nkeynes@653
   440
		for( i=0; i<strip_count; i++ ) {
nkeynes@653
   441
		    struct polygon_struct *poly = scene_add_polygon( polyaddr, 4, is_modified );
nkeynes@653
   442
		    polyaddr += polygon_length;
nkeynes@653
   443
		    if( last_poly != NULL && last_poly->next == NULL ) {
nkeynes@653
   444
			last_poly->next = poly;
nkeynes@653
   445
		    }
nkeynes@653
   446
		    last_poly = poly;
nkeynes@653
   447
		}
nkeynes@653
   448
	    } else {
nkeynes@653
   449
		/* Polygon */
nkeynes@653
   450
		int i, last = -1;
nkeynes@653
   451
		for( i=5; i>=0; i-- ) {
nkeynes@653
   452
		    if( entry & (0x40000000>>i) ) {
nkeynes@653
   453
			last = i;
nkeynes@653
   454
			break;
nkeynes@653
   455
		    }
nkeynes@653
   456
		}
nkeynes@653
   457
		if( last != -1 ) {
nkeynes@653
   458
		    scene_add_polygon( polyaddr, last+3, is_modified );
nkeynes@653
   459
		}
nkeynes@653
   460
	    }
nkeynes@653
   461
	}
nkeynes@653
   462
    } while( 1 );
nkeynes@653
   463
}
nkeynes@653
   464
nkeynes@653
   465
static void scene_extract_vertexes( pvraddr_t tile_entry )
nkeynes@653
   466
{
nkeynes@653
   467
    uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);
nkeynes@653
   468
    do {
nkeynes@653
   469
	uint32_t entry = *tile_list++;
nkeynes@653
   470
	if( entry >> 28 == 0x0F ) {
nkeynes@653
   471
	    break;
nkeynes@653
   472
	} else if( entry >> 28 == 0x0E ) {
nkeynes@653
   473
	    tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF));
nkeynes@653
   474
	} else {
nkeynes@653
   475
	    pvraddr_t polyaddr = entry&0x000FFFFF;
nkeynes@653
   476
	    int is_modified = (entry & 0x01000000) && pvr2_scene.full_shadow;
nkeynes@653
   477
	    int vertex_length = (entry >> 21) & 0x07;
nkeynes@653
   478
	    int context_length = 3;
nkeynes@653
   479
	    if( is_modified ) {
nkeynes@653
   480
		context_length = 5;
nkeynes@653
   481
		vertex_length <<=1 ;
nkeynes@653
   482
	    }
nkeynes@653
   483
	    vertex_length += 3;
nkeynes@653
   484
	    
nkeynes@653
   485
	    if( (entry & 0xE0000000) == 0x80000000 ) {
nkeynes@653
   486
		/* Triangle(s) */
nkeynes@653
   487
		int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@653
   488
		int polygon_length = 3 * vertex_length + context_length;
nkeynes@653
   489
		int i;
nkeynes@653
   490
		for( i=0; i<strip_count; i++ ) {
nkeynes@653
   491
		    scene_add_vertexes( polyaddr, vertex_length, is_modified );
nkeynes@653
   492
		    polyaddr += polygon_length;
nkeynes@653
   493
		}
nkeynes@653
   494
	    } else if( (entry & 0xE0000000) == 0xA0000000 ) {
nkeynes@653
   495
		/* Sprite(s) */
nkeynes@653
   496
		int strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@653
   497
		int polygon_length = 4 * vertex_length + context_length;
nkeynes@653
   498
		int i;
nkeynes@653
   499
		for( i=0; i<strip_count; i++ ) {
nkeynes@653
   500
		    scene_add_quad_vertexes( polyaddr, vertex_length, is_modified );
nkeynes@653
   501
		    polyaddr += polygon_length;
nkeynes@653
   502
		}
nkeynes@653
   503
	    } else {
nkeynes@653
   504
		/* Polygon */
nkeynes@653
   505
		int i, last = -1;
nkeynes@653
   506
		for( i=5; i>=0; i-- ) {
nkeynes@653
   507
		    if( entry & (0x40000000>>i) ) {
nkeynes@653
   508
			last = i;
nkeynes@653
   509
			break;
nkeynes@653
   510
		    }
nkeynes@653
   511
		}
nkeynes@653
   512
		if( last != -1 ) {
nkeynes@653
   513
		    scene_add_vertexes( polyaddr, vertex_length, is_modified );
nkeynes@653
   514
		}
nkeynes@653
   515
	    }
nkeynes@653
   516
	}
nkeynes@653
   517
    } while( 1 );    
nkeynes@653
   518
}
nkeynes@653
   519
nkeynes@653
   520
uint32_t pvr2_scene_buffer_width()
nkeynes@653
   521
{
nkeynes@653
   522
    return pvr2_scene.buffer_width;
nkeynes@653
   523
}
nkeynes@653
   524
nkeynes@653
   525
uint32_t pvr2_scene_buffer_height()
nkeynes@653
   526
{
nkeynes@653
   527
    return pvr2_scene.buffer_height;
nkeynes@653
   528
}
nkeynes@653
   529
nkeynes@653
   530
/**
nkeynes@653
   531
 * Extract the current scene into the rendering structures. We run two passes
nkeynes@653
   532
 * - first pass extracts the polygons into pvr2_scene.poly_array (finding vertex counts), 
nkeynes@653
   533
 * second pass extracts the vertex data into the VBO/vertex array.
nkeynes@653
   534
 *
nkeynes@653
   535
 * Difficult to do in single pass as we don't generally know the size of a 
nkeynes@653
   536
 * polygon for certain until we've seen all tiles containing it. It also means we
nkeynes@653
   537
 * can count the vertexes and allocate the appropriate size VBO.
nkeynes@653
   538
 *
nkeynes@653
   539
 * FIXME: accesses into VRAM need to be bounds-checked properly
nkeynes@653
   540
 */
nkeynes@653
   541
void pvr2_scene_read( void )
nkeynes@653
   542
{
nkeynes@653
   543
    pvr2_scene_init();
nkeynes@653
   544
    pvr2_scene_reset();
nkeynes@653
   545
nkeynes@653
   546
    pvr2_scene.bounds[0] = MMIO_READ( PVR2, RENDER_HCLIP ) & 0x03FF;
nkeynes@653
   547
    pvr2_scene.bounds[1] = ((MMIO_READ( PVR2, RENDER_HCLIP ) >> 16) & 0x03FF) + 1;
nkeynes@653
   548
    pvr2_scene.bounds[2] = MMIO_READ( PVR2, RENDER_VCLIP ) & 0x03FF;
nkeynes@653
   549
    pvr2_scene.bounds[3] = ((MMIO_READ( PVR2, RENDER_VCLIP ) >> 16) & 0x03FF) + 1;
nkeynes@653
   550
    pvr2_scene.bounds[4] = pvr2_scene.bounds[5] = MMIO_READF( PVR2, RENDER_FARCLIP );
nkeynes@653
   551
nkeynes@653
   552
    uint32_t *tilebuffer = (uint32_t *)(video_base + MMIO_READ( PVR2, RENDER_TILEBASE ));
nkeynes@653
   553
    uint32_t *segment = tilebuffer;
nkeynes@653
   554
    pvr2_scene.segment_list = (struct tile_segment *)tilebuffer;
nkeynes@653
   555
    pvr2_scene.pvr2_pbuf = (uint32_t *)(video_base + MMIO_READ(PVR2,RENDER_POLYBASE));
nkeynes@653
   556
    pvr2_scene.full_shadow = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100 ? FALSE : TRUE;
nkeynes@653
   557
   
nkeynes@653
   558
    int max_tile_x = 0;
nkeynes@653
   559
    int max_tile_y = 0;
nkeynes@653
   560
    int obj_config = MMIO_READ( PVR2, RENDER_OBJCFG );
nkeynes@653
   561
    int isp_config = MMIO_READ( PVR2, RENDER_ISPCFG );
nkeynes@653
   562
nkeynes@653
   563
    if( (obj_config & 0x00200000) == 0 ) {
nkeynes@653
   564
	if( isp_config & 1 ) {
nkeynes@653
   565
	    pvr2_scene.sort_mode = SORT_NEVER;
nkeynes@653
   566
	} else {
nkeynes@653
   567
	    pvr2_scene.sort_mode = SORT_ALWAYS;
nkeynes@653
   568
	}
nkeynes@653
   569
    } else {
nkeynes@653
   570
	pvr2_scene.sort_mode = SORT_TILEFLAG;
nkeynes@653
   571
    }
nkeynes@653
   572
nkeynes@653
   573
    // Pass 1: Extract polygon list 
nkeynes@653
   574
    uint32_t control;
nkeynes@653
   575
    int i;
nkeynes@653
   576
    do {
nkeynes@653
   577
	control = *segment++;
nkeynes@653
   578
	int tile_x = SEGMENT_X(control);
nkeynes@653
   579
	int tile_y = SEGMENT_Y(control);
nkeynes@653
   580
	if( tile_x > max_tile_x ) {
nkeynes@653
   581
	    max_tile_x = tile_x;
nkeynes@653
   582
	} 
nkeynes@653
   583
	if( tile_y > max_tile_y ) {
nkeynes@653
   584
	    max_tile_y = tile_y;
nkeynes@653
   585
	}
nkeynes@653
   586
	for( i=0; i<5; i++ ) {
nkeynes@653
   587
	    if( (*segment & NO_POINTER) == 0 ) {
nkeynes@653
   588
		scene_extract_polygons( *segment );
nkeynes@653
   589
	    }
nkeynes@653
   590
	    segment++;
nkeynes@653
   591
	}
nkeynes@653
   592
    } while( (control & SEGMENT_END) == 0 );
nkeynes@653
   593
nkeynes@653
   594
    pvr2_scene.buffer_width = (max_tile_x+1)<<5;
nkeynes@653
   595
    pvr2_scene.buffer_height = (max_tile_y+1)<<5;
nkeynes@653
   596
nkeynes@653
   597
    if( pvr2_scene.vertex_count > 0 ) {
nkeynes@653
   598
	// Pass 2: Extract vertex data
nkeynes@653
   599
	vertex_buffer_map();
nkeynes@653
   600
	pvr2_scene.vertex_index = 0;
nkeynes@653
   601
	segment = tilebuffer;
nkeynes@653
   602
	do {
nkeynes@653
   603
	    control = *segment++;
nkeynes@653
   604
	    for( i=0; i<5; i++ ) {
nkeynes@653
   605
		if( (*segment & NO_POINTER) == 0 ) {
nkeynes@653
   606
		    scene_extract_vertexes( *segment );
nkeynes@653
   607
		}
nkeynes@653
   608
		segment++;
nkeynes@653
   609
	    }
nkeynes@653
   610
	} while( (control & SEGMENT_END) == 0 );
nkeynes@653
   611
	vertex_buffer_unmap();
nkeynes@653
   612
    }
nkeynes@653
   613
}
nkeynes@653
   614
nkeynes@653
   615
/**
nkeynes@653
   616
 * Dump the current scene to file in a (mostly) human readable form
nkeynes@653
   617
 */
nkeynes@653
   618
void pvr2_scene_dump( FILE *f )
nkeynes@653
   619
{
nkeynes@653
   620
    int i,j;
nkeynes@653
   621
nkeynes@653
   622
    fprintf( f, "Polygons: %d\n", pvr2_scene.poly_count );
nkeynes@653
   623
    for( i=0; i<pvr2_scene.poly_count; i++ ) {
nkeynes@653
   624
	struct polygon_struct *poly = &pvr2_scene.poly_array[i];
nkeynes@669
   625
	fprintf( f, "  %08X ", ((unsigned char *)poly->context) - video_base );
nkeynes@653
   626
	switch( poly->vertex_count ) {
nkeynes@653
   627
	case 3: fprintf( f, "Tri     " ); break;
nkeynes@653
   628
	case 4: fprintf( f, "Quad    " ); break;
nkeynes@653
   629
	default: fprintf( f,"%d-Strip ", poly->vertex_count-2 ); break;
nkeynes@653
   630
	}
nkeynes@653
   631
	fprintf( f, "%08X %08X %08X ", poly->context[0], poly->context[1], poly->context[2] );
nkeynes@653
   632
	if( poly->mod_vertex_index != -1 ) {
nkeynes@653
   633
	    fprintf( f, "%08X %08X\n", poly->context[3], poly->context[5] );
nkeynes@653
   634
	} else {
nkeynes@653
   635
	    fprintf( f, "\n" );
nkeynes@653
   636
	}
nkeynes@653
   637
	
nkeynes@653
   638
	for( j=0; j<poly->vertex_count; j++ ) {
nkeynes@653
   639
	    struct vertex_struct *v = &pvr2_scene.vertex_array[poly->vertex_index+j];
nkeynes@653
   640
	    fprintf( f, "    %.5f %.5f %.5f, (%.5f,%.5f) %08X %08X\n", v->x, v->y, v->z, v->u, v->v,
nkeynes@653
   641
		     v->rgba, v->offset_rgba );
nkeynes@653
   642
	}
nkeynes@653
   643
	if( poly->mod_vertex_index != -1 ) {
nkeynes@653
   644
	    fprintf( f, "  ---\n" );
nkeynes@653
   645
	    for( j=0; j<poly->vertex_count; j++ ) {
nkeynes@653
   646
		struct vertex_struct *v = &pvr2_scene.vertex_array[poly->mod_vertex_index+j];
nkeynes@653
   647
		fprintf( f, "    %.5f %.5f %.5f, (%.5f,%.5f) %08X %08X\n", v->x, v->y, v->z, v->u, v->v,
nkeynes@653
   648
			 v->rgba, v->offset_rgba );
nkeynes@653
   649
	    }
nkeynes@653
   650
	}
nkeynes@653
   651
    }
nkeynes@653
   652
nkeynes@653
   653
}
.