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