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