Search
lxdream.org :: lxdream/src/pvr2/glrender.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/pvr2/glrender.c
changeset 1140:7dc1c71ece76
prev1139:9af81878480b
next1145:45674791c6ad
author nkeynes
date Tue Oct 26 08:39:02 2010 +1000 (13 years ago)
permissions -rw-r--r--
last change Implement fragment shader to support palette textures 'directly', and
therefore avoid having to reload all palette textures whenever the palette
changes.
file annotate diff log raw
nkeynes@639
     1
/**
nkeynes@639
     2
 * $Id$
nkeynes@639
     3
 *
nkeynes@639
     4
 * Standard OpenGL rendering engine. 
nkeynes@639
     5
 *
nkeynes@639
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@639
     7
 *
nkeynes@639
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@639
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@639
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@639
    11
 * (at your option) any later version.
nkeynes@639
    12
 *
nkeynes@639
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@639
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@639
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@639
    16
 * GNU General Public License for more details.
nkeynes@639
    17
 */
nkeynes@639
    18
nkeynes@645
    19
#include <assert.h>
nkeynes@669
    20
#include <sys/time.h>
nkeynes@639
    21
#include "display.h"
nkeynes@639
    22
#include "pvr2/pvr2.h"
nkeynes@677
    23
#include "pvr2/pvr2mmio.h"
nkeynes@639
    24
#include "pvr2/scene.h"
nkeynes@665
    25
#include "pvr2/glutil.h"
nkeynes@653
    26
nkeynes@934
    27
#define IS_EMPTY_TILE_LIST(p) ((*((uint32_t *)(pvr2_main_ram+(p))) >> 28) == 0x0F)
nkeynes@639
    28
nkeynes@645
    29
int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL,
nkeynes@736
    30
        GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, 
nkeynes@736
    31
        GL_ALWAYS };
nkeynes@645
    32
int pvr2_poly_srcblend[8] = { 
nkeynes@736
    33
        GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR,
nkeynes@736
    34
        GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, 
nkeynes@736
    35
        GL_ONE_MINUS_DST_ALPHA };
nkeynes@645
    36
int pvr2_poly_dstblend[8] = {
nkeynes@736
    37
        GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR,
nkeynes@736
    38
        GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA,
nkeynes@736
    39
        GL_ONE_MINUS_DST_ALPHA };
nkeynes@645
    40
int pvr2_poly_texblend[4] = {
nkeynes@736
    41
        GL_REPLACE, 
nkeynes@736
    42
        GL_MODULATE,  
nkeynes@736
    43
        GL_DECAL, 
nkeynes@736
    44
        GL_MODULATE 
nkeynes@645
    45
};
nkeynes@645
    46
nkeynes@1140
    47
static gboolean have_shaders = FALSE;
nkeynes@1140
    48
nkeynes@639
    49
/**
nkeynes@639
    50
 * Clip the tile bounds to the clipping plane. 
nkeynes@639
    51
 * @return TRUE if the tile was not clipped completely.
nkeynes@639
    52
 */
nkeynes@639
    53
static gboolean clip_tile_bounds( uint32_t *tile, float *clip )
nkeynes@639
    54
{
nkeynes@639
    55
    if( tile[0] < clip[0] ) tile[0] = clip[0];
nkeynes@639
    56
    if( tile[1] > clip[1] ) tile[1] = clip[1];
nkeynes@639
    57
    if( tile[2] < clip[2] ) tile[2] = clip[2];
nkeynes@639
    58
    if( tile[3] > clip[3] ) tile[3] = clip[3];
nkeynes@639
    59
    return tile[0] < tile[1] && tile[2] < tile[3];
nkeynes@639
    60
}
nkeynes@639
    61
nkeynes@645
    62
void pvr2_scene_load_textures()
nkeynes@645
    63
{
nkeynes@645
    64
    int i;
nkeynes@886
    65
    
nkeynes@1135
    66
    texcache_begin_scene( MMIO_READ( PVR2, RENDER_PALETTE ) & 0x03,
nkeynes@886
    67
                         (MMIO_READ( PVR2, RENDER_TEXSIZE ) & 0x003F) << 5 );
nkeynes@886
    68
    
nkeynes@645
    69
    for( i=0; i < pvr2_scene.poly_count; i++ ) {
nkeynes@736
    70
        struct polygon_struct *poly = &pvr2_scene.poly_array[i];
nkeynes@736
    71
        if( POLY1_TEXTURED(poly->context[0]) ) {
nkeynes@1135
    72
            poly->tex_id = texcache_get_texture( poly->context[1], poly->context[2] );
nkeynes@736
    73
            if( poly->mod_vertex_index != -1 ) {
nkeynes@863
    74
                if( pvr2_scene.shadow_mode == SHADOW_FULL ) {
nkeynes@1135
    75
                    poly->mod_tex_id = texcache_get_texture( poly->context[3], poly->context[4] );
nkeynes@863
    76
                } else {
nkeynes@863
    77
                    poly->mod_tex_id = poly->tex_id;
nkeynes@863
    78
                }
nkeynes@736
    79
            }
nkeynes@736
    80
        } else {
nkeynes@1138
    81
            poly->tex_id = 0;
nkeynes@1138
    82
            poly->mod_tex_id = 0;
nkeynes@736
    83
        }
nkeynes@645
    84
    }
nkeynes@645
    85
}
nkeynes@645
    86
nkeynes@645
    87
nkeynes@639
    88
/**
nkeynes@639
    89
 * Once-off call to setup the OpenGL context.
nkeynes@639
    90
 */
nkeynes@639
    91
void pvr2_setup_gl_context()
nkeynes@639
    92
{
nkeynes@665
    93
nkeynes@1140
    94
    if( glsl_is_supported() && isGLMultitextureSupported() ) {
nkeynes@1130
    95
        if( !glsl_load_shaders( ) ) {
nkeynes@665
    96
            WARN( "Unable to load GL shaders" );
nkeynes@1140
    97
        } else {
nkeynes@1140
    98
            have_shaders = TRUE;
nkeynes@665
    99
        }
nkeynes@665
   100
    }
nkeynes@736
   101
nkeynes@639
   102
    texcache_gl_init(); // Allocate texture IDs
nkeynes@1133
   103
    glDisable( GL_CULL_FACE );
nkeynes@639
   104
    glEnable( GL_BLEND );
nkeynes@649
   105
    glEnable( GL_DEPTH_TEST );
nkeynes@639
   106
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
nkeynes@639
   107
    glMatrixMode(GL_MODELVIEW);
nkeynes@639
   108
    glLoadIdentity();
nkeynes@639
   109
nkeynes@687
   110
#ifdef HAVE_OPENGL_CLAMP_COLOR
nkeynes@687
   111
    if( isGLExtensionSupported("GL_ARB_color_buffer_float") ) {
nkeynes@687
   112
        glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, GL_FALSE );
nkeynes@687
   113
        glClampColorARB(GL_CLAMP_FRAGMENT_COLOR_ARB, GL_FALSE );
nkeynes@687
   114
    }
nkeynes@687
   115
#endif
nkeynes@653
   116
nkeynes@639
   117
    glEnableClientState( GL_COLOR_ARRAY );
nkeynes@639
   118
    glEnableClientState( GL_VERTEX_ARRAY );
nkeynes@639
   119
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );
nkeynes@639
   120
    glEnableClientState( GL_SECONDARY_COLOR_ARRAY );
nkeynes@847
   121
    glEnableClientState( GL_FOG_COORDINATE_ARRAY_EXT );
nkeynes@639
   122
nkeynes@639
   123
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
nkeynes@639
   124
    glClearDepth(0);
nkeynes@639
   125
    glClearStencil(0);
nkeynes@1132
   126
nkeynes@1132
   127
    glFogi(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
nkeynes@1132
   128
    glFogi(GL_FOG_MODE, GL_LINEAR);
nkeynes@1132
   129
    glFogf(GL_FOG_START, 0.0);
nkeynes@1132
   130
    glFogf(GL_FOG_END, 1.0);
nkeynes@1140
   131
nkeynes@1140
   132
    if( have_shaders ) {
nkeynes@1140
   133
        glsl_set_shader(DEFAULT_PROGRAM);
nkeynes@1140
   134
        glsl_set_uniform_int(DEFAULT_PROGRAM, "primary_texture", 0);
nkeynes@1140
   135
        glsl_set_uniform_int(DEFAULT_PROGRAM, "palette_texture", 1);
nkeynes@1140
   136
        glsl_clear_shader();
nkeynes@1140
   137
    }
nkeynes@639
   138
}
nkeynes@639
   139
nkeynes@864
   140
/**
nkeynes@864
   141
 * Setup the basic context that's shared between normal and modified modes -
nkeynes@864
   142
 * depth, culling
nkeynes@864
   143
 */
nkeynes@1137
   144
static void render_set_base_context( uint32_t poly1, gboolean set_depth )
nkeynes@864
   145
{
nkeynes@1137
   146
    if( set_depth ) {
nkeynes@865
   147
        glDepthFunc( POLY1_DEPTH_MODE(poly1) );
nkeynes@865
   148
    }
nkeynes@865
   149
nkeynes@864
   150
    glDepthMask( POLY1_DEPTH_WRITE(poly1) ? GL_TRUE : GL_FALSE );
nkeynes@865
   151
}
nkeynes@864
   152
nkeynes@865
   153
/**
nkeynes@865
   154
 * Setup the texture/shading settings (TSP) which vary between mod/unmod modes.
nkeynes@865
   155
 */
nkeynes@1137
   156
void render_set_tsp_context( uint32_t poly1, uint32_t poly2 )
nkeynes@865
   157
{
nkeynes@863
   158
    glShadeModel( POLY1_SHADE_MODEL(poly1) );
nkeynes@1140
   159
nkeynes@1140
   160
    if( POLY1_TEXTURED(poly1) && !have_shaders ) {
nkeynes@1139
   161
        if( POLY2_TEX_BLEND(poly2) == 2 )
nkeynes@1139
   162
            glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL );
nkeynes@1139
   163
        else
nkeynes@1139
   164
            glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
nkeynes@1140
   165
nkeynes@863
   166
     }
nkeynes@1132
   167
nkeynes@863
   168
     switch( POLY2_FOG_MODE(poly2) ) {
nkeynes@863
   169
     case PVR2_POLY_FOG_LOOKUP:
nkeynes@863
   170
         glFogfv( GL_FOG_COLOR, pvr2_scene.fog_lut_colour );
nkeynes@863
   171
         break;
nkeynes@863
   172
     case PVR2_POLY_FOG_VERTEX:
nkeynes@1132
   173
         glFogfv( GL_FOG_COLOR, pvr2_scene.fog_vert_colour );
nkeynes@1132
   174
         break;
nkeynes@863
   175
     }
nkeynes@653
   176
nkeynes@863
   177
     int srcblend = POLY2_SRC_BLEND(poly2);
nkeynes@863
   178
     int destblend = POLY2_DEST_BLEND(poly2);
nkeynes@863
   179
     glBlendFunc( srcblend, destblend );
nkeynes@863
   180
nkeynes@863
   181
     if( POLY2_SRC_BLEND_TARGET(poly2) || POLY2_DEST_BLEND_TARGET(poly2) ) {
nkeynes@863
   182
         WARN( "Accumulation buffer not supported" );
nkeynes@863
   183
     }   
nkeynes@863
   184
}
nkeynes@863
   185
nkeynes@645
   186
/**
nkeynes@645
   187
 * Setup the GL context for the supplied polygon context.
nkeynes@645
   188
 * @param context pointer to 3 or 5 words of polygon context
nkeynes@865
   189
 * @param depth_mode force depth mode, or 0 to use the polygon's
nkeynes@865
   190
 * depth mode.
nkeynes@645
   191
 */
nkeynes@1137
   192
void render_set_context( uint32_t *context, gboolean set_depth )
nkeynes@645
   193
{
nkeynes@1137
   194
    render_set_base_context(context[0], set_depth);
nkeynes@1137
   195
    render_set_tsp_context(context[0],context[1]);
nkeynes@645
   196
}
nkeynes@645
   197
nkeynes@1133
   198
static inline void gl_draw_vertexes( struct polygon_struct *poly )
nkeynes@1133
   199
{
nkeynes@1133
   200
    do {
nkeynes@1133
   201
        glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index, poly->vertex_count);
nkeynes@1133
   202
        poly = poly->sub_next;
nkeynes@1133
   203
    } while( poly != NULL );
nkeynes@1133
   204
}
nkeynes@1133
   205
nkeynes@1133
   206
static inline void gl_draw_mod_vertexes( struct polygon_struct *poly )
nkeynes@1133
   207
{
nkeynes@1133
   208
    do {
nkeynes@1133
   209
        glDrawArrays(GL_TRIANGLE_STRIP, poly->mod_vertex_index, poly->vertex_count);
nkeynes@1133
   210
        poly = poly->sub_next;
nkeynes@1133
   211
    } while( poly != NULL );
nkeynes@1133
   212
}
nkeynes@645
   213
nkeynes@1137
   214
static void gl_render_poly( struct polygon_struct *poly, gboolean set_depth)
nkeynes@639
   215
{
nkeynes@1133
   216
    if( poly->vertex_count == 0 )
nkeynes@1133
   217
        return; /* Culled */
nkeynes@1133
   218
nkeynes@1138
   219
    glBindTexture(GL_TEXTURE_2D, poly->tex_id);
nkeynes@863
   220
    if( poly->mod_vertex_index == -1 ) {
nkeynes@1137
   221
        render_set_context( poly->context, set_depth );
nkeynes@1133
   222
        gl_draw_vertexes(poly);
nkeynes@864
   223
    }  else {
nkeynes@864
   224
        glEnable( GL_STENCIL_TEST );
nkeynes@1137
   225
        render_set_base_context( poly->context[0], set_depth );
nkeynes@1137
   226
        render_set_tsp_context( poly->context[0], poly->context[1] );
nkeynes@864
   227
        glStencilFunc(GL_EQUAL, 0, 2);
nkeynes@1133
   228
        gl_draw_vertexes(poly);
nkeynes@863
   229
nkeynes@863
   230
        if( pvr2_scene.shadow_mode == SHADOW_FULL ) {
nkeynes@1138
   231
            if( poly->mod_tex_id != poly->tex_id ) {
nkeynes@863
   232
                glBindTexture(GL_TEXTURE_2D, poly->mod_tex_id);
nkeynes@863
   233
            }
nkeynes@1137
   234
            render_set_tsp_context( poly->context[0], poly->context[3] );
nkeynes@863
   235
        }
nkeynes@864
   236
        glStencilFunc(GL_EQUAL, 2, 2);
nkeynes@1133
   237
        gl_draw_mod_vertexes(poly);
nkeynes@1136
   238
        glDisable( GL_STENCIL_TEST );
nkeynes@863
   239
    }
nkeynes@639
   240
}
nkeynes@639
   241
nkeynes@687
   242
static void gl_render_bkgnd( struct polygon_struct *poly )
nkeynes@639
   243
{
nkeynes@1138
   244
    glBindTexture(GL_TEXTURE_2D, poly->tex_id);
nkeynes@1137
   245
    render_set_tsp_context( poly->context[0], poly->context[1] );
nkeynes@687
   246
    glDisable( GL_DEPTH_TEST );
nkeynes@687
   247
    glBlendFunc( GL_ONE, GL_ZERO );
nkeynes@1133
   248
    gl_draw_vertexes(poly);
nkeynes@687
   249
    glEnable( GL_DEPTH_TEST );
nkeynes@687
   250
}
nkeynes@687
   251
nkeynes@1137
   252
void gl_render_tilelist( pvraddr_t tile_entry, gboolean set_depth )
nkeynes@653
   253
{
nkeynes@934
   254
    uint32_t *tile_list = (uint32_t *)(pvr2_main_ram+tile_entry);
nkeynes@639
   255
    int strip_count;
nkeynes@639
   256
    struct polygon_struct *poly;
nkeynes@639
   257
nkeynes@863
   258
    if( !IS_TILE_PTR(tile_entry) )
nkeynes@863
   259
        return;
nkeynes@863
   260
nkeynes@639
   261
    while(1) {
nkeynes@736
   262
        uint32_t entry = *tile_list++;
nkeynes@736
   263
        switch( entry >> 28 ) {
nkeynes@736
   264
        case 0x0F:
nkeynes@736
   265
            return; // End-of-list
nkeynes@736
   266
        case 0x0E:
nkeynes@934
   267
            tile_list = (uint32_t *)(pvr2_main_ram + (entry&0x007FFFFF));
nkeynes@736
   268
            break;
nkeynes@736
   269
        case 0x08: case 0x09: case 0x0A: case 0x0B:
nkeynes@736
   270
            strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@736
   271
            poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
nkeynes@736
   272
            while( strip_count > 0 ) {
nkeynes@736
   273
                assert( poly != NULL );
nkeynes@1137
   274
                gl_render_poly( poly, set_depth );
nkeynes@736
   275
                poly = poly->next;
nkeynes@736
   276
                strip_count--;
nkeynes@736
   277
            }
nkeynes@736
   278
            break;
nkeynes@736
   279
        default:
nkeynes@736
   280
            if( entry & 0x7E000000 ) {
nkeynes@736
   281
                poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
nkeynes@1137
   282
                gl_render_poly( poly, set_depth );
nkeynes@736
   283
            }
nkeynes@736
   284
        }
nkeynes@863
   285
    }       
nkeynes@863
   286
}
nkeynes@863
   287
nkeynes@863
   288
/**
nkeynes@863
   289
 * Render the tilelist with depthbuffer updates only. 
nkeynes@863
   290
 */
nkeynes@863
   291
void gl_render_tilelist_depthonly( pvraddr_t tile_entry )
nkeynes@863
   292
{
nkeynes@934
   293
    uint32_t *tile_list = (uint32_t *)(pvr2_main_ram+tile_entry);
nkeynes@863
   294
    int strip_count;
nkeynes@863
   295
    struct polygon_struct *poly;
nkeynes@863
   296
    
nkeynes@863
   297
    if( !IS_TILE_PTR(tile_entry) )
nkeynes@863
   298
        return;
nkeynes@863
   299
nkeynes@863
   300
    while(1) {
nkeynes@863
   301
        uint32_t entry = *tile_list++;
nkeynes@863
   302
        switch( entry >> 28 ) {
nkeynes@863
   303
        case 0x0F:
nkeynes@863
   304
            return; // End-of-list
nkeynes@863
   305
        case 0x0E:
nkeynes@934
   306
            tile_list = (uint32_t *)(pvr2_main_ram + (entry&0x007FFFFF));
nkeynes@863
   307
            break;
nkeynes@863
   308
        case 0x08: case 0x09: case 0x0A: case 0x0B:
nkeynes@863
   309
            strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@863
   310
            poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
nkeynes@863
   311
            while( strip_count > 0 ) {
nkeynes@1133
   312
                if( poly->vertex_count != 0 ) {
nkeynes@1137
   313
                    render_set_base_context(poly->context[0],TRUE);
nkeynes@1133
   314
                    gl_draw_vertexes(poly);
nkeynes@1133
   315
                }
nkeynes@863
   316
                poly = poly->next;
nkeynes@863
   317
                strip_count--;
nkeynes@863
   318
            }
nkeynes@863
   319
            break;
nkeynes@863
   320
        default:
nkeynes@863
   321
            if( entry & 0x7E000000 ) {
nkeynes@863
   322
                poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
nkeynes@1133
   323
                if( poly->vertex_count != 0 ) {
nkeynes@1137
   324
                    render_set_base_context(poly->context[0],TRUE);
nkeynes@1133
   325
                    gl_draw_vertexes(poly);
nkeynes@1133
   326
                }
nkeynes@863
   327
            }
nkeynes@863
   328
        }
nkeynes@863
   329
    }           
nkeynes@863
   330
}
nkeynes@863
   331
nkeynes@864
   332
static void drawrect2d( uint32_t tile_bounds[], float z )
nkeynes@864
   333
{
nkeynes@864
   334
    glBegin( GL_QUADS );
nkeynes@864
   335
    glVertex3f( tile_bounds[0], tile_bounds[2], z );
nkeynes@864
   336
    glVertex3f( tile_bounds[1], tile_bounds[2], z );
nkeynes@864
   337
    glVertex3f( tile_bounds[1], tile_bounds[3], z );
nkeynes@864
   338
    glVertex3f( tile_bounds[0], tile_bounds[3], z );
nkeynes@864
   339
    glEnd();
nkeynes@864
   340
}
nkeynes@864
   341
nkeynes@864
   342
void gl_render_modifier_polygon( struct polygon_struct *poly, uint32_t tile_bounds[] )
nkeynes@864
   343
{
nkeynes@864
   344
    /* A bit of explanation:
nkeynes@864
   345
     * In theory it works like this: generate a 1-bit stencil for each polygon
nkeynes@864
   346
     * volume, and then AND or OR it against the overall 1-bit tile stencil at 
nkeynes@864
   347
     * the end of the volume. 
nkeynes@864
   348
     * 
nkeynes@864
   349
     * The implementation here uses a 2-bit stencil buffer, where each volume
nkeynes@864
   350
     * is drawn using only stencil bit 0, and then a 'flush' polygon is drawn
nkeynes@864
   351
     * to update bit 1 accordingly and clear bit 0.
nkeynes@864
   352
     * 
nkeynes@864
   353
     * This could probably be more efficient, but at least it works correctly 
nkeynes@864
   354
     * now :)
nkeynes@864
   355
     */
nkeynes@864
   356
    
nkeynes@1133
   357
    if( poly->vertex_count == 0 )
nkeynes@1133
   358
        return; /* Culled */
nkeynes@1133
   359
nkeynes@1133
   360
    gl_draw_vertexes(poly);
nkeynes@1133
   361
nkeynes@1133
   362
nkeynes@864
   363
    
nkeynes@864
   364
    int poly_type = POLY1_VOLUME_MODE(poly->context[0]);
nkeynes@864
   365
    if( poly_type == PVR2_VOLUME_REGION0 ) {
nkeynes@864
   366
        /* 00 => 00
nkeynes@864
   367
         * 01 => 00
nkeynes@864
   368
         * 10 => 10
nkeynes@864
   369
         * 11 => 00
nkeynes@864
   370
         */
nkeynes@864
   371
        glStencilMask( 0x03 );
nkeynes@864
   372
        glStencilFunc(GL_EQUAL, 0x02, 0x03);
nkeynes@864
   373
        glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);
nkeynes@864
   374
        glDisable( GL_DEPTH_TEST );
nkeynes@864
   375
nkeynes@864
   376
        drawrect2d( tile_bounds, pvr2_scene.bounds[4] );
nkeynes@864
   377
        
nkeynes@864
   378
        glEnable( GL_DEPTH_TEST );
nkeynes@864
   379
        glStencilMask( 0x01 );
nkeynes@864
   380
        glStencilFunc( GL_ALWAYS, 0, 1 );
nkeynes@864
   381
        glStencilOp( GL_KEEP,GL_INVERT, GL_KEEP ); 
nkeynes@864
   382
    } else if( poly_type == PVR2_VOLUME_REGION1 ) {
nkeynes@864
   383
        /* This is harder with the standard stencil ops - do it in two passes
nkeynes@864
   384
         * 00 => 00 | 00 => 10
nkeynes@864
   385
         * 01 => 10 | 01 => 10
nkeynes@864
   386
         * 10 => 10 | 10 => 00
nkeynes@864
   387
         * 11 => 10 | 11 => 10
nkeynes@864
   388
         */
nkeynes@864
   389
        glStencilMask( 0x02 );
nkeynes@864
   390
        glStencilOp( GL_INVERT, GL_INVERT, GL_INVERT );
nkeynes@864
   391
        glDisable( GL_DEPTH_TEST );
nkeynes@864
   392
        
nkeynes@864
   393
        drawrect2d( tile_bounds, pvr2_scene.bounds[4] );
nkeynes@864
   394
        
nkeynes@864
   395
        glStencilMask( 0x03 );
nkeynes@864
   396
        glStencilFunc( GL_NOTEQUAL,0x02, 0x03);
nkeynes@864
   397
        glStencilOp( GL_ZERO, GL_REPLACE, GL_REPLACE );
nkeynes@864
   398
        
nkeynes@864
   399
        drawrect2d( tile_bounds, pvr2_scene.bounds[4] );
nkeynes@864
   400
        
nkeynes@864
   401
        glEnable( GL_DEPTH_TEST );
nkeynes@864
   402
        glStencilMask( 0x01 );
nkeynes@864
   403
        glStencilFunc( GL_ALWAYS, 0, 1 );
nkeynes@864
   404
        glStencilOp( GL_KEEP,GL_INVERT, GL_KEEP );         
nkeynes@864
   405
    }
nkeynes@864
   406
}
nkeynes@864
   407
nkeynes@864
   408
void gl_render_modifier_tilelist( pvraddr_t tile_entry, uint32_t tile_bounds[] )
nkeynes@863
   409
{
nkeynes@934
   410
    uint32_t *tile_list = (uint32_t *)(pvr2_main_ram+tile_entry);
nkeynes@863
   411
    int strip_count;
nkeynes@863
   412
    struct polygon_struct *poly;
nkeynes@863
   413
nkeynes@863
   414
    if( !IS_TILE_PTR(tile_entry) )
nkeynes@863
   415
        return;
nkeynes@863
   416
nkeynes@863
   417
    glEnable( GL_STENCIL_TEST );
nkeynes@863
   418
    glEnable( GL_DEPTH_TEST );
nkeynes@863
   419
    glDepthFunc( GL_LEQUAL );
nkeynes@863
   420
    
nkeynes@863
   421
    glStencilFunc( GL_ALWAYS, 0, 1 );
nkeynes@863
   422
    glStencilOp( GL_KEEP,GL_INVERT, GL_KEEP ); 
nkeynes@864
   423
    glStencilMask( 0x01 );
nkeynes@863
   424
    glDepthMask( GL_FALSE );
nkeynes@863
   425
    
nkeynes@863
   426
    while(1) {
nkeynes@863
   427
        uint32_t entry = *tile_list++;
nkeynes@863
   428
        switch( entry >> 28 ) {
nkeynes@863
   429
        case 0x0F:
nkeynes@863
   430
            glDepthMask( GL_TRUE );
nkeynes@863
   431
            glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
nkeynes@1136
   432
            glDisable( GL_STENCIL_TEST );
nkeynes@863
   433
            return; // End-of-list
nkeynes@863
   434
        case 0x0E:
nkeynes@934
   435
            tile_list = (uint32_t *)(pvr2_main_ram + (entry&0x007FFFFF));
nkeynes@863
   436
            break;
nkeynes@863
   437
        case 0x08: case 0x09: case 0x0A: case 0x0B:
nkeynes@863
   438
            strip_count = ((entry >> 25) & 0x0F)+1;
nkeynes@863
   439
            poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
nkeynes@863
   440
            while( strip_count > 0 ) {
nkeynes@864
   441
                gl_render_modifier_polygon( poly, tile_bounds );
nkeynes@863
   442
                poly = poly->next;
nkeynes@863
   443
                strip_count--;
nkeynes@863
   444
            }
nkeynes@863
   445
            break;
nkeynes@863
   446
        default:
nkeynes@863
   447
            if( entry & 0x7E000000 ) {
nkeynes@863
   448
                poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];
nkeynes@864
   449
                gl_render_modifier_polygon( poly, tile_bounds );
nkeynes@863
   450
            }
nkeynes@863
   451
        }
nkeynes@863
   452
    }
nkeynes@863
   453
    
nkeynes@639
   454
}
nkeynes@639
   455
nkeynes@639
   456
nkeynes@639
   457
/**
nkeynes@639
   458
 * Render the currently defined scene in pvr2_scene
nkeynes@639
   459
 */
nkeynes@639
   460
void pvr2_scene_render( render_buffer_t buffer )
nkeynes@639
   461
{
nkeynes@639
   462
    /* Scene setup */
nkeynes@645
   463
    struct timeval start_tv, tex_tv, end_tv;
nkeynes@645
   464
nkeynes@645
   465
    gettimeofday(&start_tv, NULL);
nkeynes@639
   466
    display_driver->set_render_target(buffer);
nkeynes@639
   467
    pvr2_check_palette_changed();
nkeynes@645
   468
    pvr2_scene_load_textures();
nkeynes@736
   469
nkeynes@645
   470
    gettimeofday( &tex_tv, NULL );
nkeynes@645
   471
    uint32_t ms = (tex_tv.tv_sec - start_tv.tv_sec) * 1000 +
nkeynes@736
   472
    (tex_tv.tv_usec - start_tv.tv_usec)/1000;
nkeynes@645
   473
    DEBUG( "Scene setup in %dms", ms );
nkeynes@639
   474
nkeynes@639
   475
    /* Setup view projection matrix */
nkeynes@639
   476
    glMatrixMode(GL_PROJECTION);
nkeynes@639
   477
    glLoadIdentity();
nkeynes@639
   478
    float nearz = pvr2_scene.bounds[4];
nkeynes@639
   479
    float farz = pvr2_scene.bounds[5];
nkeynes@639
   480
    if( nearz == farz ) {
nkeynes@687
   481
        farz*= 4.0;
nkeynes@639
   482
    }
nkeynes@639
   483
    glOrtho( 0, pvr2_scene.buffer_width, pvr2_scene.buffer_height, 0, 
nkeynes@736
   484
             -farz, -nearz );
nkeynes@649
   485
    float alphaRef = ((float)(MMIO_READ(PVR2, RENDER_ALPHA_REF)&0xFF)+1)/256.0;
nkeynes@649
   486
    glAlphaFunc( GL_GEQUAL, alphaRef );
nkeynes@639
   487
nkeynes@639
   488
    /* Clear the buffer (FIXME: May not want always want to do this) */
nkeynes@639
   489
    glDisable( GL_SCISSOR_TEST );
nkeynes@651
   490
    glDepthMask( GL_TRUE );
nkeynes@864
   491
    glStencilMask( 0x03 );
nkeynes@639
   492
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
nkeynes@639
   493
nkeynes@639
   494
    /* Setup vertex array pointers */
nkeynes@687
   495
    glVertexPointer(3, GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].x);
nkeynes@687
   496
    glColorPointer(4, GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].rgba[0]);
nkeynes@1140
   497
    glTexCoordPointer(4, GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].u);
nkeynes@687
   498
    glSecondaryColorPointerEXT(3, GL_FLOAT, sizeof(struct vertex_struct), pvr2_scene.vertex_array[0].offset_rgba );
nkeynes@847
   499
    glFogCoordPointerEXT(GL_FLOAT, sizeof(struct vertex_struct), &pvr2_scene.vertex_array[0].offset_rgba[3] );
nkeynes@669
   500
    /* Turn on the shaders (if available) */
nkeynes@1130
   501
    glsl_set_shader(DEFAULT_PROGRAM);
nkeynes@639
   502
nkeynes@687
   503
    /* Render the background */
nkeynes@687
   504
    gl_render_bkgnd( pvr2_scene.bkgnd_poly );
nkeynes@736
   505
nkeynes@639
   506
    glEnable( GL_SCISSOR_TEST );
nkeynes@1132
   507
    glEnable( GL_COLOR_SUM );
nkeynes@1132
   508
    glEnable( GL_FOG );
nkeynes@1138
   509
    glEnable( GL_TEXTURE_2D );
nkeynes@639
   510
nkeynes@639
   511
    /* Process the segment list */
nkeynes@639
   512
    struct tile_segment *segment = pvr2_scene.segment_list;
nkeynes@639
   513
    do {
nkeynes@736
   514
        int tilex = SEGMENT_X(segment->control);
nkeynes@736
   515
        int tiley = SEGMENT_Y(segment->control);
nkeynes@639
   516
nkeynes@736
   517
        uint32_t tile_bounds[4] = { tilex << 5, (tilex+1)<<5, tiley<<5, (tiley+1)<<5 };
nkeynes@736
   518
        if( !clip_tile_bounds(tile_bounds, pvr2_scene.bounds) ) {
nkeynes@736
   519
            continue; // fully clipped, skip tile
nkeynes@736
   520
        }
nkeynes@736
   521
nkeynes@736
   522
        /* Clip to the visible part of the tile */
nkeynes@736
   523
        glScissor( tile_bounds[0], pvr2_scene.buffer_height-tile_bounds[3], 
nkeynes@736
   524
                   tile_bounds[1]-tile_bounds[0], tile_bounds[3] - tile_bounds[2] );
nkeynes@864
   525
        if( display_driver->capabilities.stencil_bits >= 2 && 
nkeynes@863
   526
                IS_TILE_PTR(segment->opaquemod_ptr) &&
nkeynes@863
   527
                !IS_EMPTY_TILE_LIST(segment->opaquemod_ptr) ) {
nkeynes@863
   528
            /* Don't do this unless there's actually some shadow polygons */
nkeynes@863
   529
nkeynes@863
   530
            /* Use colormask instead of drawbuffer for simplicity */
nkeynes@863
   531
            glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
nkeynes@863
   532
            gl_render_tilelist_depthonly(segment->opaque_ptr);
nkeynes@864
   533
            gl_render_modifier_tilelist(segment->opaquemod_ptr, tile_bounds);
nkeynes@863
   534
            glClear( GL_DEPTH_BUFFER_BIT );
nkeynes@863
   535
            glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
nkeynes@736
   536
        }
nkeynes@1137
   537
        gl_render_tilelist(segment->opaque_ptr,TRUE);
nkeynes@863
   538
        if( IS_TILE_PTR(segment->punchout_ptr) ) {
nkeynes@863
   539
            glEnable(GL_ALPHA_TEST );
nkeynes@1137
   540
            glDepthFunc(GL_GEQUAL);
nkeynes@1137
   541
            gl_render_tilelist(segment->punchout_ptr, FALSE );
nkeynes@863
   542
            glDisable(GL_ALPHA_TEST );
nkeynes@863
   543
        }
nkeynes@1133
   544
nkeynes@736
   545
        if( IS_TILE_PTR(segment->trans_ptr) ) {
nkeynes@736
   546
            if( pvr2_scene.sort_mode == SORT_NEVER || 
nkeynes@736
   547
                    (pvr2_scene.sort_mode == SORT_TILEFLAG && (segment->control&SEGMENT_SORT_TRANS))) {
nkeynes@1137
   548
                gl_render_tilelist(segment->trans_ptr, TRUE);
nkeynes@736
   549
            } else {
nkeynes@736
   550
                render_autosort_tile(segment->trans_ptr, RENDER_NORMAL );
nkeynes@736
   551
            }
nkeynes@736
   552
        }
nkeynes@639
   553
    } while( !IS_LAST_SEGMENT(segment++) );
nkeynes@639
   554
    glDisable( GL_SCISSOR_TEST );
nkeynes@1132
   555
    glDisable( GL_COLOR_SUM );
nkeynes@1132
   556
    glDisable( GL_FOG );
nkeynes@1130
   557
    glsl_clear_shader();
nkeynes@669
   558
nkeynes@645
   559
    gettimeofday( &end_tv, NULL );
nkeynes@645
   560
    ms = (end_tv.tv_sec - tex_tv.tv_sec) * 1000 +
nkeynes@736
   561
    (end_tv.tv_usec - tex_tv.tv_usec)/1000;
nkeynes@645
   562
    DEBUG( "Scene render in %dms", ms );
nkeynes@639
   563
}
.