Search
lxdream.org :: lxdream :: r864:a90f3d5e57e1
lxdream 0.9.1
released Jun 29
Download Now
changeset864:a90f3d5e57e1
parent863:a5e5310061e2
child865:e10c081f4b81
authornkeynes
dateMon Sep 29 05:55:33 2008 +0000 (11 years ago)
Compute accurate shadow volume stencils
src/pvr2/glrender.c
src/pvr2/pvr2.h
1.1 --- a/src/pvr2/glrender.c Sun Sep 28 01:09:51 2008 +0000
1.2 +++ b/src/pvr2/glrender.c Mon Sep 29 05:55:33 2008 +0000
1.3 @@ -122,15 +122,8 @@
1.4 glClearStencil(0);
1.5 }
1.6
1.7 -/**
1.8 - * Setup the basic context that's shared between normal and modified modes -
1.9 - * depth, culling, shade model, and color sum
1.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.27
1.28 +/**
1.29 + * Setup the basic context that's shared between normal and modified modes -
1.30 + * depth, culling
1.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.40
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.57
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.71
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 polygon
1.87 + * volume, and then AND or OR it against the overall 1-bit tile stencil at
1.88 + * the end of the volume.
1.89 + *
1.90 + * The implementation here uses a 2-bit stencil buffer, where each volume
1.91 + * is drawn using only stencil bit 0, and then a 'flush' polygon is drawn
1.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 correctly
1.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 => 00
1.104 + * 01 => 00
1.105 + * 10 => 10
1.106 + * 11 => 00
1.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 passes
1.122 + * 00 => 00 | 00 => 10
1.123 + * 01 => 10 | 01 => 10
1.124 + * 10 => 10 | 10 => 00
1.125 + * 11 => 10 | 11 => 10
1.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.152
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.158
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.184
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 +0000
2.2 +++ b/src/pvr2/pvr2.h Mon Sep 29 05:55:33 2008 +0000
2.3 @@ -87,6 +87,10 @@
2.4 #define PVR2_CMD_VERTEX 0xE0
2.5 #define PVR2_CMD_VERTEX_LAST 0xF0
2.6
2.7 +#define PVR2_VOLUME_NORMAL 0x00000000
2.8 +#define PVR2_VOLUME_REGION1 0x20000000
2.9 +#define PVR2_VOLUME_REGION0 0x40000000
2.10 +
2.11 #define PVR2_POLY_TEXTURED 0x00000008
2.12 #define PVR2_POLY_SPECULAR 0x00000004
2.13 #define PVR2_POLY_SHADED 0x00000002
2.14 @@ -352,6 +356,7 @@
2.15 void pvr2_queue_gun_event( int xpos, int ypos );
2.16
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)
.