revision 864:a90f3d5e57e1
summary |
tree |
shortlog |
changelog |
graph |
changeset |
raw | bz2 | zip | gz changeset | 864:a90f3d5e57e1 |
parent | 863:a5e5310061e2 |
child | 865:e10c081f4b81 |
author | nkeynes |
date | Mon Sep 29 05:55:33 2008 +0000 (15 years ago) |
Compute accurate shadow volume stencils
src/pvr2/glrender.c | view | annotate | diff | log | ||
src/pvr2/pvr2.h | view | annotate | diff | log |
1.1 --- a/src/pvr2/glrender.c Sun Sep 28 01:09:51 2008 +00001.2 +++ b/src/pvr2/glrender.c Mon Sep 29 05:55:33 2008 +00001.3 @@ -122,15 +122,8 @@1.4 glClearStencil(0);1.5 }1.7 -/**1.8 - * Setup the basic context that's shared between normal and modified modes -1.9 - * depth, culling, shade model, and color sum1.10 - */1.11 -static void render_set_base_context( uint32_t poly1 )1.12 +static void render_set_cull( uint32_t poly1 )1.13 {1.14 - glDepthFunc( POLY1_DEPTH_MODE(poly1) );1.15 - glDepthMask( POLY1_DEPTH_WRITE(poly1) ? GL_TRUE : GL_FALSE );1.16 -1.17 switch( POLY1_CULL_MODE(poly1) ) {1.18 case CULL_NONE:1.19 case CULL_SMALL:1.20 @@ -144,8 +137,20 @@1.21 glEnable( GL_CULL_FACE );1.22 glFrontFace( GL_CCW );1.23 break;1.24 - }1.25 + }1.26 +}1.28 +/**1.29 + * Setup the basic context that's shared between normal and modified modes -1.30 + * depth, culling1.31 + */1.32 +static void render_set_base_context( uint32_t poly1 )1.33 +{1.34 + glDepthFunc( POLY1_DEPTH_MODE(poly1) );1.35 + glDepthMask( POLY1_DEPTH_WRITE(poly1) ? GL_TRUE : GL_FALSE );1.36 +1.37 + render_set_cull( poly1 );1.38 +1.39 glShadeModel( POLY1_SHADE_MODEL(poly1) );1.41 if( POLY1_SPECULAR(poly1) ) {1.42 @@ -233,12 +238,14 @@1.43 glBindTexture(GL_TEXTURE_2D, poly->tex_id);1.44 }1.45 if( poly->mod_vertex_index == -1 ) {1.46 + glDisable( GL_STENCIL_TEST );1.47 render_set_context( poly->context, RENDER_NORMAL );1.48 glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index, poly->vertex_count );1.49 - } else {1.50 + } else {1.51 + glEnable( GL_STENCIL_TEST );1.52 render_set_base_context( poly->context[0] );1.53 render_set_tsp_context( poly->context[0], poly->context[1], poly->context[2] );1.54 - glStencilFunc(GL_EQUAL, 0, 1);1.55 + glStencilFunc(GL_EQUAL, 0, 2);1.56 glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index, poly->vertex_count );1.58 if( pvr2_scene.shadow_mode == SHADOW_FULL ) {1.59 @@ -247,7 +254,7 @@1.60 }1.61 render_set_tsp_context( poly->context[0], poly->context[3], poly->context[4] );1.62 }1.63 - glStencilFunc(GL_EQUAL, 1, 1);1.64 + glStencilFunc(GL_EQUAL, 2, 2);1.65 glDrawArrays(GL_TRIANGLE_STRIP, poly->mod_vertex_index, poly->vertex_count );1.66 }1.67 }1.68 @@ -346,7 +353,81 @@1.69 }1.70 }1.72 -void gl_render_modifier_tilelist( pvraddr_t tile_entry )1.73 +static void drawrect2d( uint32_t tile_bounds[], float z )1.74 +{1.75 + glBegin( GL_QUADS );1.76 + glVertex3f( tile_bounds[0], tile_bounds[2], z );1.77 + glVertex3f( tile_bounds[1], tile_bounds[2], z );1.78 + glVertex3f( tile_bounds[1], tile_bounds[3], z );1.79 + glVertex3f( tile_bounds[0], tile_bounds[3], z );1.80 + glEnd();1.81 +}1.82 +1.83 +void gl_render_modifier_polygon( struct polygon_struct *poly, uint32_t tile_bounds[] )1.84 +{1.85 + /* A bit of explanation:1.86 + * In theory it works like this: generate a 1-bit stencil for each polygon1.87 + * volume, and then AND or OR it against the overall 1-bit tile stencil at1.88 + * the end of the volume.1.89 + *1.90 + * The implementation here uses a 2-bit stencil buffer, where each volume1.91 + * is drawn using only stencil bit 0, and then a 'flush' polygon is drawn1.92 + * to update bit 1 accordingly and clear bit 0.1.93 + *1.94 + * This could probably be more efficient, but at least it works correctly1.95 + * now :)1.96 + */1.97 +1.98 + render_set_cull(poly->context[0]);1.99 + glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index, poly->vertex_count );1.100 +1.101 + int poly_type = POLY1_VOLUME_MODE(poly->context[0]);1.102 + if( poly_type == PVR2_VOLUME_REGION0 ) {1.103 + /* 00 => 001.104 + * 01 => 001.105 + * 10 => 101.106 + * 11 => 001.107 + */1.108 + glStencilMask( 0x03 );1.109 + glStencilFunc(GL_EQUAL, 0x02, 0x03);1.110 + glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);1.111 + glDisable( GL_CULL_FACE );1.112 + glDisable( GL_DEPTH_TEST );1.113 +1.114 + drawrect2d( tile_bounds, pvr2_scene.bounds[4] );1.115 +1.116 + glEnable( GL_DEPTH_TEST );1.117 + glStencilMask( 0x01 );1.118 + glStencilFunc( GL_ALWAYS, 0, 1 );1.119 + glStencilOp( GL_KEEP,GL_INVERT, GL_KEEP );1.120 + } else if( poly_type == PVR2_VOLUME_REGION1 ) {1.121 + /* This is harder with the standard stencil ops - do it in two passes1.122 + * 00 => 00 | 00 => 101.123 + * 01 => 10 | 01 => 101.124 + * 10 => 10 | 10 => 001.125 + * 11 => 10 | 11 => 101.126 + */1.127 + glStencilMask( 0x02 );1.128 + glStencilOp( GL_INVERT, GL_INVERT, GL_INVERT );1.129 + glDisable( GL_CULL_FACE );1.130 + glDisable( GL_DEPTH_TEST );1.131 +1.132 + drawrect2d( tile_bounds, pvr2_scene.bounds[4] );1.133 +1.134 + glStencilMask( 0x03 );1.135 + glStencilFunc( GL_NOTEQUAL,0x02, 0x03);1.136 + glStencilOp( GL_ZERO, GL_REPLACE, GL_REPLACE );1.137 +1.138 + drawrect2d( tile_bounds, pvr2_scene.bounds[4] );1.139 +1.140 + glEnable( GL_DEPTH_TEST );1.141 + glStencilMask( 0x01 );1.142 + glStencilFunc( GL_ALWAYS, 0, 1 );1.143 + glStencilOp( GL_KEEP,GL_INVERT, GL_KEEP );1.144 + }1.145 +}1.146 +1.147 +void gl_render_modifier_tilelist( pvraddr_t tile_entry, uint32_t tile_bounds[] )1.148 {1.149 uint32_t *tile_list = (uint32_t *)(video_base+tile_entry);1.150 int strip_count;1.151 @@ -365,7 +446,7 @@1.153 glStencilFunc( GL_ALWAYS, 0, 1 );1.154 glStencilOp( GL_KEEP,GL_INVERT, GL_KEEP );1.155 -1.156 + glStencilMask( 0x01 );1.157 glDepthMask( GL_FALSE );1.159 while(1) {1.160 @@ -382,7 +463,7 @@1.161 strip_count = ((entry >> 25) & 0x0F)+1;1.162 poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];1.163 while( strip_count > 0 ) {1.164 - glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index, poly->vertex_count );1.165 + gl_render_modifier_polygon( poly, tile_bounds );1.166 poly = poly->next;1.167 strip_count--;1.168 }1.169 @@ -390,7 +471,7 @@1.170 default:1.171 if( entry & 0x7E000000 ) {1.172 poly = pvr2_scene.buf_to_poly_map[entry&0x000FFFFF];1.173 - glDrawArrays(GL_TRIANGLE_STRIP, poly->vertex_index, poly->vertex_count );1.174 + gl_render_modifier_polygon( poly, tile_bounds );1.175 }1.176 }1.177 }1.178 @@ -432,6 +513,7 @@1.179 /* Clear the buffer (FIXME: May not want always want to do this) */1.180 glDisable( GL_SCISSOR_TEST );1.181 glDepthMask( GL_TRUE );1.182 + glStencilMask( 0x03 );1.183 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );1.185 /* Setup vertex array pointers */1.186 @@ -466,7 +548,7 @@1.187 /* Clip to the visible part of the tile */1.188 glScissor( tile_bounds[0], pvr2_scene.buffer_height-tile_bounds[3],1.189 tile_bounds[1]-tile_bounds[0], tile_bounds[3] - tile_bounds[2] );1.190 - if( display_driver->capabilities.stencil_bits != 0 &&1.191 + if( display_driver->capabilities.stencil_bits >= 2 &&1.192 IS_TILE_PTR(segment->opaquemod_ptr) &&1.193 !IS_EMPTY_TILE_LIST(segment->opaquemod_ptr) ) {1.194 /* Don't do this unless there's actually some shadow polygons */1.195 @@ -474,7 +556,7 @@1.196 /* Use colormask instead of drawbuffer for simplicity */1.197 glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );1.198 gl_render_tilelist_depthonly(segment->opaque_ptr);1.199 - gl_render_modifier_tilelist(segment->opaquemod_ptr);1.200 + gl_render_modifier_tilelist(segment->opaquemod_ptr, tile_bounds);1.201 glClear( GL_DEPTH_BUFFER_BIT );1.202 glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );1.203 }
2.1 --- a/src/pvr2/pvr2.h Sun Sep 28 01:09:51 2008 +00002.2 +++ b/src/pvr2/pvr2.h Mon Sep 29 05:55:33 2008 +00002.3 @@ -87,6 +87,10 @@2.4 #define PVR2_CMD_VERTEX 0xE02.5 #define PVR2_CMD_VERTEX_LAST 0xF02.7 +#define PVR2_VOLUME_NORMAL 0x000000002.8 +#define PVR2_VOLUME_REGION1 0x200000002.9 +#define PVR2_VOLUME_REGION0 0x400000002.10 +2.11 #define PVR2_POLY_TEXTURED 0x000000082.12 #define PVR2_POLY_SPECULAR 0x000000042.13 #define PVR2_POLY_SHADED 0x000000022.14 @@ -352,6 +356,7 @@2.15 void pvr2_queue_gun_event( int xpos, int ypos );2.17 /************************* Rendering support macros **************************/2.18 +#define POLY1_VOLUME_MODE(poly1) ((poly1)&0xE0000000)2.19 #define POLY1_DEPTH_MODE(poly1) ( pvr2_poly_depthmode[(poly1)>>29] )2.20 #define POLY1_DEPTH_WRITE(poly1) (((poly1)&0x04000000) == 0 )2.21 #define POLY1_CULL_MODE(poly1) (((poly1)>>27)&0x03)
.