nkeynes@189: /** nkeynes@561: * $Id$ nkeynes@189: * nkeynes@189: * PVR2 renderer core. nkeynes@189: * nkeynes@189: * Copyright (c) 2005 Nathan Keynes. nkeynes@189: * nkeynes@189: * This program is free software; you can redistribute it and/or modify nkeynes@189: * it under the terms of the GNU General Public License as published by nkeynes@189: * the Free Software Foundation; either version 2 of the License, or nkeynes@189: * (at your option) any later version. nkeynes@189: * nkeynes@189: * This program is distributed in the hope that it will be useful, nkeynes@189: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@189: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@189: * GNU General Public License for more details. nkeynes@189: */ nkeynes@215: #include nkeynes@189: #include "pvr2/pvr2.h" nkeynes@189: #include "asic.h" nkeynes@540: #include "display.h" nkeynes@429: nkeynes@221: int pvr2_poly_depthmode[8] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, nkeynes@189: GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, nkeynes@189: GL_ALWAYS }; nkeynes@221: int pvr2_poly_srcblend[8] = { nkeynes@189: GL_ZERO, GL_ONE, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, nkeynes@189: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, nkeynes@189: GL_ONE_MINUS_DST_ALPHA }; nkeynes@221: int pvr2_poly_dstblend[8] = { nkeynes@189: GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, nkeynes@189: GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, nkeynes@189: GL_ONE_MINUS_DST_ALPHA }; nkeynes@221: int pvr2_poly_texblend[4] = { nkeynes@322: GL_REPLACE, nkeynes@322: GL_MODULATE, nkeynes@322: GL_DECAL, nkeynes@322: GL_MODULATE nkeynes@322: }; nkeynes@221: int pvr2_render_colour_format[8] = { nkeynes@477: COLFMT_BGRA1555, COLFMT_RGB565, COLFMT_BGRA4444, COLFMT_BGRA1555, nkeynes@477: COLFMT_BGR888, COLFMT_BGRA8888, COLFMT_BGRA8888, COLFMT_BGRA4444 }; nkeynes@189: nkeynes@189: nkeynes@189: #define CULL_NONE 0 nkeynes@189: #define CULL_SMALL 1 nkeynes@189: #define CULL_CCW 2 nkeynes@189: #define CULL_CW 3 nkeynes@189: nkeynes@189: #define SEGMENT_END 0x80000000 nkeynes@298: #define SEGMENT_ZCLEAR 0x40000000 nkeynes@189: #define SEGMENT_SORT_TRANS 0x20000000 nkeynes@189: #define SEGMENT_START 0x10000000 nkeynes@189: #define SEGMENT_X(c) (((c) >> 2) & 0x3F) nkeynes@189: #define SEGMENT_Y(c) (((c) >> 8) & 0x3F) nkeynes@189: #define NO_POINTER 0x80000000 nkeynes@189: nkeynes@189: extern char *video_base; nkeynes@189: nkeynes@322: gboolean pvr2_force_fragment_alpha = FALSE; nkeynes@338: gboolean pvr2_debug_render = FALSE; nkeynes@318: nkeynes@189: struct tile_segment { nkeynes@189: uint32_t control; nkeynes@189: pvraddr_t opaque_ptr; nkeynes@189: pvraddr_t opaquemod_ptr; nkeynes@189: pvraddr_t trans_ptr; nkeynes@189: pvraddr_t transmod_ptr; nkeynes@189: pvraddr_t punchout_ptr; nkeynes@189: }; nkeynes@189: nkeynes@341: void render_print_tilelist( FILE *f, uint32_t tile_entry ); nkeynes@341: nkeynes@189: /** nkeynes@189: * Convert a half-float (16-bit) FP number to a regular 32-bit float. nkeynes@189: * Source is 1-bit sign, 5-bit exponent, 10-bit mantissa. nkeynes@189: * TODO: Check the correctness of this. nkeynes@189: */ nkeynes@189: float halftofloat( uint16_t half ) nkeynes@189: { nkeynes@189: union { nkeynes@189: float f; nkeynes@189: uint32_t i; nkeynes@189: } temp; nkeynes@308: /* int e = ((half & 0x7C00) >> 10) - 15 + 127; nkeynes@189: nkeynes@189: temp.i = ((half & 0x8000) << 16) | (e << 23) | nkeynes@308: ((half & 0x03FF) << 13); */ nkeynes@308: temp.i = ((uint32_t)half)<<16; nkeynes@189: return temp.f; nkeynes@189: } nkeynes@189: nkeynes@189: nkeynes@189: /** nkeynes@189: * Setup the GL context for the supplied polygon context. nkeynes@189: * @param context pointer to 3 or 5 words of polygon context nkeynes@189: * @param modified boolean flag indicating that the modified nkeynes@189: * version should be used, rather than the normal version. nkeynes@189: */ nkeynes@189: void render_set_context( uint32_t *context, int render_mode ) nkeynes@189: { nkeynes@189: uint32_t poly1 = context[0], poly2, texture; nkeynes@189: if( render_mode == RENDER_FULLMOD ) { nkeynes@189: poly2 = context[3]; nkeynes@189: texture = context[4]; nkeynes@189: } else { nkeynes@189: poly2 = context[1]; nkeynes@189: texture = context[2]; nkeynes@189: } nkeynes@338: nkeynes@189: if( POLY1_DEPTH_ENABLE(poly1) ) { nkeynes@189: glEnable( GL_DEPTH_TEST ); nkeynes@189: glDepthFunc( POLY1_DEPTH_MODE(poly1) ); nkeynes@189: } else { nkeynes@189: glDisable( GL_DEPTH_TEST ); nkeynes@189: } nkeynes@189: nkeynes@189: switch( POLY1_CULL_MODE(poly1) ) { nkeynes@189: case CULL_NONE: nkeynes@189: case CULL_SMALL: nkeynes@189: glDisable( GL_CULL_FACE ); nkeynes@189: break; nkeynes@189: case CULL_CCW: nkeynes@189: glEnable( GL_CULL_FACE ); nkeynes@189: glFrontFace( GL_CW ); nkeynes@189: break; nkeynes@189: case CULL_CW: nkeynes@189: glEnable( GL_CULL_FACE ); nkeynes@189: glFrontFace( GL_CCW ); nkeynes@189: break; nkeynes@189: } nkeynes@189: nkeynes@318: if( POLY1_SPECULAR(poly1) ) { nkeynes@318: glEnable(GL_COLOR_SUM); nkeynes@318: } else { nkeynes@318: glDisable(GL_COLOR_SUM); nkeynes@318: } nkeynes@318: nkeynes@338: pvr2_force_fragment_alpha = POLY2_ALPHA_ENABLE(poly2) ? FALSE : TRUE; nkeynes@338: nkeynes@189: if( POLY1_TEXTURED(poly1) ) { nkeynes@189: int width = POLY2_TEX_WIDTH(poly2); nkeynes@189: int height = POLY2_TEX_HEIGHT(poly2); nkeynes@189: glEnable(GL_TEXTURE_2D); nkeynes@286: texcache_get_texture( (texture&0x000FFFFF)<<3, width, height, texture ); nkeynes@338: switch( POLY2_TEX_BLEND(poly2) ) { nkeynes@338: case 0: /* Replace */ nkeynes@338: glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); nkeynes@338: break; nkeynes@338: case 2:/* Decal */ nkeynes@338: glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL ); nkeynes@338: break; nkeynes@338: case 1: /* Modulate RGB */ nkeynes@338: /* This is not directly supported by opengl (other than by mucking nkeynes@338: * with the texture format), but we get the same effect by forcing nkeynes@338: * the fragment alpha to 1.0 and using GL_MODULATE. nkeynes@338: */ nkeynes@338: pvr2_force_fragment_alpha = TRUE; nkeynes@338: case 3: /* Modulate RGBA */ nkeynes@338: glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ); nkeynes@338: break; nkeynes@338: } nkeynes@352: nkeynes@308: if( POLY2_TEX_CLAMP_U(poly2) ) { nkeynes@308: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); nkeynes@308: } else { nkeynes@308: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT ); nkeynes@308: } nkeynes@308: if( POLY2_TEX_CLAMP_V(poly2) ) { nkeynes@308: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); nkeynes@308: } else { nkeynes@350: glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT ); nkeynes@308: } nkeynes@189: } else { nkeynes@189: glDisable( GL_TEXTURE_2D ); nkeynes@189: } nkeynes@189: nkeynes@189: glShadeModel( POLY1_SHADE_MODEL(poly1) ); nkeynes@189: nkeynes@221: int srcblend = POLY2_SRC_BLEND(poly2); nkeynes@221: int destblend = POLY2_DEST_BLEND(poly2); nkeynes@221: glBlendFunc( srcblend, destblend ); nkeynes@318: nkeynes@322: if( POLY2_SRC_BLEND_TARGET(poly2) || POLY2_DEST_BLEND_TARGET(poly2) ) { nkeynes@322: ERROR( "Accumulation buffer not supported" ); nkeynes@322: } nkeynes@338: nkeynes@318: nkeynes@189: } nkeynes@189: nkeynes@319: #define FARGB_A(x) (((float)(((x)>>24)+1))/256.0) nkeynes@319: #define FARGB_R(x) (((float)((((x)>>16)&0xFF)+1))/256.0) nkeynes@319: #define FARGB_G(x) (((float)((((x)>>8)&0xFF)+1))/256.0) nkeynes@319: #define FARGB_B(x) (((float)(((x)&0xFF)+1))/256.0) nkeynes@319: nkeynes@319: void render_unpack_vertexes( struct vertex_unpacked *out, uint32_t poly1, nkeynes@319: uint32_t *vertexes, int num_vertexes, nkeynes@319: int vertex_size, int render_mode ) nkeynes@319: { nkeynes@319: int m = 0, i; nkeynes@319: if( render_mode == RENDER_FULLMOD ) { nkeynes@319: m = (vertex_size - 3)/2; nkeynes@319: } nkeynes@319: nkeynes@319: for( i=0; i>16); nkeynes@319: out[i].v = halftofloat(vertexes[k]); nkeynes@319: k++; nkeynes@319: } else { nkeynes@319: out[i].u = vertexf[k]; nkeynes@319: out[i].v = vertexf[k+1]; nkeynes@319: k+=2; nkeynes@319: } nkeynes@319: } else { nkeynes@319: out[i].u = 0; nkeynes@319: out[i].v = 0; nkeynes@319: } nkeynes@319: uint32_t argb = vertexes[k++]; nkeynes@319: out[i].rgba[0] = FARGB_R(argb); nkeynes@319: out[i].rgba[1] = FARGB_G(argb); nkeynes@319: out[i].rgba[2] = FARGB_B(argb); nkeynes@319: out[i].rgba[3] = FARGB_A(argb); nkeynes@319: if( POLY1_SPECULAR(poly1) ) { nkeynes@319: uint32_t offset = vertexes[k++]; nkeynes@429: out[i].offset_rgba[0] = FARGB_R(offset); nkeynes@429: out[i].offset_rgba[1] = FARGB_G(offset); nkeynes@429: out[i].offset_rgba[2] = FARGB_B(offset); nkeynes@429: out[i].offset_rgba[3] = FARGB_A(offset); nkeynes@319: } nkeynes@319: vertexes += vertex_size; nkeynes@319: } nkeynes@319: } nkeynes@319: nkeynes@319: /** nkeynes@319: * Unpack the vertexes for a quad, calculating the values for the last nkeynes@319: * vertex. nkeynes@319: * FIXME: Integrate this with rendbkg somehow nkeynes@319: */ nkeynes@319: void render_unpack_quad( struct vertex_unpacked *unpacked, uint32_t poly1, nkeynes@319: uint32_t *vertexes, int vertex_size, nkeynes@319: int render_mode ) nkeynes@319: { nkeynes@319: int i; nkeynes@319: struct vertex_unpacked diff0, diff1; nkeynes@319: nkeynes@319: render_unpack_vertexes( unpacked, poly1, vertexes, 3, vertex_size, render_mode ); nkeynes@319: nkeynes@319: diff0.x = unpacked[0].x - unpacked[1].x; nkeynes@319: diff0.y = unpacked[0].y - unpacked[1].y; nkeynes@319: diff1.x = unpacked[2].x - unpacked[1].x; nkeynes@319: diff1.y = unpacked[2].y - unpacked[1].y; nkeynes@319: nkeynes@319: float detxy = ((diff1.y) * (diff0.x)) - ((diff0.y) * (diff1.x)); nkeynes@319: float *vertexf = (float *)(vertexes+(vertex_size*3)); nkeynes@319: if( detxy == 0 ) { nkeynes@319: memcpy( &unpacked[3], &unpacked[2], sizeof(struct vertex_unpacked) ); nkeynes@319: unpacked[3].x = vertexf[0]; nkeynes@319: unpacked[3].y = vertexf[1]; nkeynes@319: return; nkeynes@319: } nkeynes@319: nkeynes@319: unpacked[3].x = vertexf[0]; nkeynes@319: unpacked[3].y = vertexf[1]; nkeynes@319: float t = ((unpacked[3].x - unpacked[1].x) * diff1.y - nkeynes@319: (unpacked[3].y - unpacked[1].y) * diff1.x) / detxy; nkeynes@319: float s = ((unpacked[3].y - unpacked[1].y) * diff0.x - nkeynes@319: (unpacked[3].x - unpacked[1].x) * diff0.y) / detxy; nkeynes@331: diff0.z = (1/unpacked[0].z) - (1/unpacked[1].z); nkeynes@331: diff1.z = (1/unpacked[2].z) - (1/unpacked[1].z); nkeynes@331: unpacked[3].z = 1/((1/unpacked[1].z) + (t*diff0.z) + (s*diff1.z)); nkeynes@319: nkeynes@319: diff0.u = unpacked[0].u - unpacked[1].u; nkeynes@319: diff0.v = unpacked[0].v - unpacked[1].v; nkeynes@319: diff1.u = unpacked[2].u - unpacked[1].u; nkeynes@319: diff1.v = unpacked[2].v - unpacked[1].v; nkeynes@319: unpacked[3].u = unpacked[1].u + (t*diff0.u) + (s*diff1.u); nkeynes@319: unpacked[3].v = unpacked[1].v + (t*diff0.v) + (s*diff1.v); nkeynes@319: nkeynes@319: if( !POLY1_GOURAUD_SHADED(poly1) ) { nkeynes@319: memcpy( unpacked[3].rgba, unpacked[2].rgba, sizeof(unpacked[2].rgba) ); nkeynes@319: memcpy( unpacked[3].offset_rgba, unpacked[2].offset_rgba, sizeof(unpacked[2].offset_rgba) ); nkeynes@319: } else { nkeynes@319: for( i=0; i<4; i++ ) { nkeynes@319: float d0 = unpacked[0].rgba[i] - unpacked[1].rgba[i]; nkeynes@319: float d1 = unpacked[2].rgba[i] - unpacked[1].rgba[i]; nkeynes@319: unpacked[3].rgba[i] = unpacked[1].rgba[i] + (t*d0) + (s*d1); nkeynes@319: d0 = unpacked[0].offset_rgba[i] - unpacked[1].offset_rgba[i]; nkeynes@319: d1 = unpacked[2].offset_rgba[i] - unpacked[1].offset_rgba[i]; nkeynes@319: unpacked[3].offset_rgba[i] = unpacked[1].offset_rgba[i] + (t*d0) + (s*d1); nkeynes@319: } nkeynes@319: } nkeynes@319: } nkeynes@319: nkeynes@319: void render_unpacked_vertex_array( uint32_t poly1, struct vertex_unpacked *vertexes[], nkeynes@319: int num_vertexes ) { nkeynes@319: int i; nkeynes@319: nkeynes@319: glBegin( GL_TRIANGLE_STRIP ); nkeynes@319: nkeynes@319: for( i=0; iu, vertexes[i]->v ); nkeynes@319: } nkeynes@319: nkeynes@322: if( pvr2_force_fragment_alpha ) { nkeynes@322: glColor4f( vertexes[i]->rgba[0], vertexes[i]->rgba[1], vertexes[i]->rgba[2], 1.0 ); nkeynes@322: } else { nkeynes@322: glColor4f( vertexes[i]->rgba[0], vertexes[i]->rgba[1], vertexes[i]->rgba[2], nkeynes@322: vertexes[i]->rgba[3] ); nkeynes@322: } nkeynes@319: if( POLY1_SPECULAR(poly1) ) { nkeynes@319: glSecondaryColor3fEXT( vertexes[i]->offset_rgba[0], nkeynes@319: vertexes[i]->offset_rgba[1], nkeynes@319: vertexes[i]->offset_rgba[2] ); nkeynes@319: } nkeynes@331: glVertex3f( vertexes[i]->x, vertexes[i]->y, 1/vertexes[i]->z ); nkeynes@319: } nkeynes@319: nkeynes@319: glEnd(); nkeynes@319: } nkeynes@319: nkeynes@319: void render_quad_vertexes( uint32_t poly1, uint32_t *vertexes, int vertex_size, int render_mode ) nkeynes@319: { nkeynes@319: struct vertex_unpacked unpacked[4]; nkeynes@319: struct vertex_unpacked *pt[4] = {&unpacked[0], &unpacked[1], &unpacked[3], &unpacked[2]}; nkeynes@319: render_unpack_quad( unpacked, poly1, vertexes, vertex_size, render_mode ); nkeynes@319: render_unpacked_vertex_array( poly1, pt, 4 ); nkeynes@319: } nkeynes@319: nkeynes@319: void render_vertex_array( uint32_t poly1, uint32_t *vert_array[], int num_vertexes, int vertex_size, nkeynes@319: int render_mode ) nkeynes@189: { nkeynes@189: int i, m=0; nkeynes@189: nkeynes@189: if( render_mode == RENDER_FULLMOD ) { nkeynes@189: m = (vertex_size - 3)/2; nkeynes@189: } nkeynes@189: nkeynes@189: glBegin( GL_TRIANGLE_STRIP ); nkeynes@189: nkeynes@189: for( i=0; i>16), nkeynes@318: halftofloat(vertexes[k]) ); nkeynes@318: k++; nkeynes@189: } else { nkeynes@318: glTexCoord2f( vertexf[k], vertexf[k+1] ); nkeynes@318: k+=2; nkeynes@189: } nkeynes@189: } nkeynes@189: nkeynes@318: argb = vertexes[k++]; nkeynes@318: if( pvr2_force_fragment_alpha ) { nkeynes@318: glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8), nkeynes@318: (GLubyte)argb, 0xFF ); nkeynes@318: } else { nkeynes@318: glColor4ub( (GLubyte)(argb >> 16), (GLubyte)(argb >> 8), nkeynes@318: (GLubyte)argb, (GLubyte)(argb >> 24) ); nkeynes@318: } nkeynes@318: nkeynes@318: if( POLY1_SPECULAR(poly1) ) { nkeynes@318: uint32_t spec = vertexes[k++]; nkeynes@318: glSecondaryColor3ubEXT( (GLubyte)(spec >> 16), (GLubyte)(spec >> 8), nkeynes@318: (GLubyte)spec ); nkeynes@318: } nkeynes@331: glVertex3f( vertexf[0], vertexf[1], 1/vertexf[2] ); nkeynes@189: vertexes += vertex_size; nkeynes@189: } nkeynes@189: nkeynes@189: glEnd(); nkeynes@189: } nkeynes@189: nkeynes@319: void render_vertexes( uint32_t poly1, uint32_t *vertexes, int num_vertexes, int vertex_size, nkeynes@319: int render_mode ) nkeynes@319: { nkeynes@319: uint32_t *vert_array[num_vertexes]; nkeynes@319: int i; nkeynes@319: for( i=0; i> 28 == 0x0F ) { nkeynes@189: break; nkeynes@189: } else if( entry >> 28 == 0x0E ) { nkeynes@189: tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF)); nkeynes@189: } else { nkeynes@215: uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2)); nkeynes@189: int is_modified = entry & 0x01000000; nkeynes@189: int vertex_length = (entry >> 21) & 0x07; nkeynes@189: int context_length = 3; nkeynes@189: if( is_modified && !cheap_modifier_mode ) { nkeynes@189: context_length = 5; nkeynes@189: vertex_length *= 2 ; nkeynes@189: } nkeynes@189: vertex_length += 3; nkeynes@308: nkeynes@189: if( (entry & 0xE0000000) == 0x80000000 ) { nkeynes@189: /* Triangle(s) */ nkeynes@189: int strip_count = ((entry >> 25) & 0x0F)+1; nkeynes@189: int polygon_length = 3 * vertex_length + context_length; nkeynes@189: int i; nkeynes@189: for( i=0; i> 25) & 0x0F)+1; nkeynes@189: int polygon_length = 4 * vertex_length + context_length; nkeynes@189: int i; nkeynes@189: for( i=0; i>i) ) { nkeynes@189: if( first == -1 ) first = i; nkeynes@189: last = i; nkeynes@189: } nkeynes@189: } nkeynes@189: if( first != -1 ) { nkeynes@189: first = 0; nkeynes@189: render_set_context(polygon, render_mode); nkeynes@189: render_vertexes( *polygon, polygon+context_length + (first*vertex_length), nkeynes@477: (last-first+3), vertex_length, render_mode ); nkeynes@189: } nkeynes@189: } nkeynes@189: } nkeynes@189: } while( 1 ); nkeynes@189: } nkeynes@189: nkeynes@189: void pvr2_render_tilebuffer( int width, int height, int clipx1, int clipy1, nkeynes@189: int clipx2, int clipy2 ) { nkeynes@189: nkeynes@191: pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE ); nkeynes@189: int tile_sort; nkeynes@189: gboolean cheap_shadow; nkeynes@189: nkeynes@191: int obj_config = MMIO_READ( PVR2, RENDER_OBJCFG ); nkeynes@191: int isp_config = MMIO_READ( PVR2, RENDER_ISPCFG ); nkeynes@191: int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW ); nkeynes@189: nkeynes@222: if( (obj_config & 0x00200000) == 0 ) { nkeynes@189: if( isp_config & 1 ) { nkeynes@189: tile_sort = 0; nkeynes@189: } else { nkeynes@189: tile_sort = 2; nkeynes@189: } nkeynes@189: } else { nkeynes@189: tile_sort = 1; nkeynes@189: } nkeynes@189: nkeynes@189: cheap_shadow = shadow_cfg & 0x100 ? TRUE : FALSE; nkeynes@189: nkeynes@189: struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase); nkeynes@189: nkeynes@189: glEnable( GL_SCISSOR_TEST ); nkeynes@268: do { nkeynes@221: // fwrite_dump32v( (uint32_t *)segment, sizeof(struct tile_segment), 6, stderr ); nkeynes@189: int tilex = SEGMENT_X(segment->control); nkeynes@189: int tiley = SEGMENT_Y(segment->control); nkeynes@189: nkeynes@189: int x1 = tilex << 5; nkeynes@189: int y1 = tiley << 5; nkeynes@189: if( x1 + 32 <= clipx1 || nkeynes@189: y1 + 32 <= clipy1 || nkeynes@189: x1 >= clipx2 || nkeynes@189: y1 >= clipy2 ) { nkeynes@189: /* Tile completely clipped, skip */ nkeynes@189: continue; nkeynes@189: } nkeynes@215: nkeynes@189: /* Set a scissor on the visible part of the tile */ nkeynes@189: int w = MIN(x1+32, clipx2) - x1; nkeynes@189: int h = MIN(y1+32, clipy2) - y1; nkeynes@189: x1 = MAX(x1,clipx1); nkeynes@189: y1 = MAX(y1,clipy1); nkeynes@189: glScissor( x1, height-y1-h, w, h ); nkeynes@189: nkeynes@189: if( (segment->opaque_ptr & NO_POINTER) == 0 ) { nkeynes@338: if( pvr2_debug_render ) { nkeynes@338: fprintf( stderr, "Tile %d,%d Opaque\n", tilex, tiley ); nkeynes@341: render_print_tilelist( stderr, segment->opaque_ptr ); nkeynes@338: } nkeynes@189: if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) { nkeynes@189: /* TODO */ nkeynes@189: } nkeynes@189: render_tile( segment->opaque_ptr, RENDER_NORMAL, cheap_shadow ); nkeynes@189: } nkeynes@189: nkeynes@189: if( (segment->trans_ptr & NO_POINTER) == 0 ) { nkeynes@338: if( pvr2_debug_render ) { nkeynes@338: fprintf( stderr, "Tile %d,%d Trans\n", tilex, tiley ); nkeynes@341: render_print_tilelist( stderr, segment->trans_ptr ); nkeynes@338: } nkeynes@189: if( (segment->transmod_ptr & NO_POINTER) == 0 ) { nkeynes@189: /* TODO */ nkeynes@189: } nkeynes@222: if( tile_sort == 2 || nkeynes@222: (tile_sort == 1 && ((segment->control & SEGMENT_SORT_TRANS)==0)) ) { nkeynes@189: render_autosort_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow ); nkeynes@189: } else { nkeynes@189: render_tile( segment->trans_ptr, RENDER_NORMAL, cheap_shadow ); nkeynes@189: } nkeynes@189: } nkeynes@189: nkeynes@189: if( (segment->punchout_ptr & NO_POINTER) == 0 ) { nkeynes@338: if( pvr2_debug_render ) { nkeynes@338: fprintf( stderr, "Tile %d,%d Punchout\n", tilex, tiley ); nkeynes@341: render_print_tilelist( stderr, segment->punchout_ptr ); nkeynes@338: } nkeynes@189: render_tile( segment->punchout_ptr, RENDER_NORMAL, cheap_shadow ); nkeynes@189: } nkeynes@268: } while( ((segment++)->control & SEGMENT_END) == 0 ); nkeynes@189: glDisable( GL_SCISSOR_TEST ); nkeynes@189: } nkeynes@322: nkeynes@322: static float render_find_maximum_tile_z( pvraddr_t tile_entry, float inputz ) nkeynes@322: { nkeynes@322: uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE); nkeynes@322: uint32_t *tile_list = (uint32_t *)(video_base+tile_entry); nkeynes@322: int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100; nkeynes@322: int i, j; nkeynes@322: float z = inputz; nkeynes@322: do { nkeynes@322: uint32_t entry = *tile_list++; nkeynes@322: if( entry >> 28 == 0x0F ) { nkeynes@322: break; nkeynes@322: } else if( entry >> 28 == 0x0E ) { nkeynes@322: tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF)); nkeynes@322: } else { nkeynes@322: uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2)); nkeynes@322: int vertex_length = (entry >> 21) & 0x07; nkeynes@322: int context_length = 3; nkeynes@351: if( (entry & 0x01000000) && (shadow_cfg==0) ) { nkeynes@322: context_length = 5; nkeynes@322: vertex_length *= 2 ; nkeynes@322: } nkeynes@322: vertex_length += 3; nkeynes@322: if( (entry & 0xE0000000) == 0x80000000 ) { nkeynes@322: /* Triangle(s) */ nkeynes@322: int strip_count = ((entry >> 25) & 0x0F)+1; nkeynes@322: float *vertexz = (float *)(polygon+context_length+2); nkeynes@322: for( i=0; i z ) { nkeynes@322: z = *vertexz; nkeynes@322: } nkeynes@322: vertexz += vertex_length; nkeynes@322: } nkeynes@322: vertexz += context_length; nkeynes@322: } nkeynes@322: } else if( (entry & 0xE0000000) == 0xA0000000 ) { nkeynes@322: /* Sprite(s) */ nkeynes@322: int strip_count = ((entry >> 25) & 0x0F)+1; nkeynes@322: int i; nkeynes@322: float *vertexz = (float *)(polygon+context_length+2); nkeynes@322: for( i=0; i z ) { nkeynes@322: z = *vertexz; nkeynes@322: } nkeynes@322: vertexz += vertex_length; nkeynes@322: } nkeynes@322: vertexz+=context_length; nkeynes@322: } nkeynes@322: } else { nkeynes@322: /* Polygon */ nkeynes@429: int i; nkeynes@322: float *vertexz = (float *)polygon+context_length+2; nkeynes@322: for( i=0; i<6; i++ ) { nkeynes@322: if( (entry & (0x40000000>>i)) && *vertexz > z ) { nkeynes@322: z = *vertexz; nkeynes@322: } nkeynes@322: vertexz += vertex_length; nkeynes@322: } nkeynes@322: } nkeynes@322: } nkeynes@322: } while(1); nkeynes@322: return z; nkeynes@322: } nkeynes@322: nkeynes@322: /** nkeynes@322: * Scan through the scene to determine the largest z value (in order to set up nkeynes@322: * an appropriate near clip plane). nkeynes@322: */ nkeynes@322: float pvr2_render_find_maximum_z( ) nkeynes@322: { nkeynes@322: pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE ); nkeynes@322: float maximumz = MMIO_READF( PVR2, RENDER_FARCLIP ); /* Initialize to the far clip plane */ nkeynes@322: nkeynes@322: struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase); nkeynes@322: do { nkeynes@322: nkeynes@322: if( (segment->opaque_ptr & NO_POINTER) == 0 ) { nkeynes@322: maximumz = render_find_maximum_tile_z(segment->opaque_ptr, maximumz); nkeynes@322: } nkeynes@322: if( (segment->opaquemod_ptr & NO_POINTER) == 0 ) { nkeynes@322: maximumz = render_find_maximum_tile_z(segment->opaquemod_ptr, maximumz); nkeynes@322: } nkeynes@322: if( (segment->trans_ptr & NO_POINTER) == 0 ) { nkeynes@322: maximumz = render_find_maximum_tile_z(segment->trans_ptr, maximumz); nkeynes@322: } nkeynes@322: if( (segment->transmod_ptr & NO_POINTER) == 0 ) { nkeynes@322: maximumz = render_find_maximum_tile_z(segment->transmod_ptr, maximumz); nkeynes@322: } nkeynes@322: if( (segment->punchout_ptr & NO_POINTER) == 0 ) { nkeynes@322: maximumz = render_find_maximum_tile_z(segment->punchout_ptr, maximumz); nkeynes@322: } nkeynes@322: nkeynes@322: } while( ((segment++)->control & SEGMENT_END) == 0 ); nkeynes@322: nkeynes@331: return 1/maximumz; nkeynes@322: } nkeynes@338: nkeynes@338: /** nkeynes@338: * Scan the segment info to determine the width and height of the render (in nkeynes@338: * pixels). nkeynes@338: * @param x,y output values to receive the width and height info. nkeynes@338: */ nkeynes@338: void pvr2_render_getsize( int *x, int *y ) nkeynes@338: { nkeynes@338: pvraddr_t segmentbase = MMIO_READ( PVR2, RENDER_TILEBASE ); nkeynes@338: int maxx = 0, maxy = 0; nkeynes@338: nkeynes@338: struct tile_segment *segment = (struct tile_segment *)(video_base + segmentbase); nkeynes@338: do { nkeynes@338: int tilex = SEGMENT_X(segment->control); nkeynes@338: int tiley = SEGMENT_Y(segment->control); nkeynes@338: if( tilex > maxx ) { nkeynes@338: maxx = tilex; nkeynes@338: } nkeynes@338: if( tiley > maxy ) { nkeynes@338: maxy = tiley; nkeynes@338: } nkeynes@338: } while( ((segment++)->control & SEGMENT_END) == 0 ); nkeynes@338: nkeynes@338: *x = (maxx+1)<<5; nkeynes@338: *y = (maxy+1)<<5; nkeynes@338: } nkeynes@341: nkeynes@341: void render_print_vertexes( FILE *f, uint32_t poly1, uint32_t *vert_array[], nkeynes@341: int num_vertexes, int vertex_size ) nkeynes@341: { nkeynes@341: char buf[256], *p; nkeynes@429: int i, k; nkeynes@341: for( i=0; i>16), nkeynes@341: halftofloat(verti[k]) ); nkeynes@341: k++; nkeynes@341: } else { nkeynes@341: p += sprintf( p, "uv=%9.5f,%9.5f ", vertf[k], vertf[k+1] ); nkeynes@341: k+=2; nkeynes@341: } nkeynes@341: } nkeynes@341: nkeynes@341: p += sprintf( p, "%08X ", verti[k++] ); nkeynes@341: if( POLY1_SPECULAR(poly1) ) { nkeynes@341: p += sprintf( p, "%08X", verti[k++] ); nkeynes@341: } nkeynes@341: p += sprintf( p, "\n" ); nkeynes@341: fprintf( f, buf ); nkeynes@341: } nkeynes@341: } nkeynes@341: nkeynes@341: void render_print_polygon( FILE *f, uint32_t entry ) nkeynes@341: { nkeynes@341: uint32_t poly_bank = MMIO_READ(PVR2,RENDER_POLYBASE); nkeynes@341: int shadow_cfg = MMIO_READ( PVR2, RENDER_SHADOW ) & 0x100; nkeynes@429: int i; nkeynes@341: nkeynes@341: if( entry >> 28 == 0x0F ) { nkeynes@341: fprintf( f, "EOT\n" ); nkeynes@341: } else if( entry >> 28 == 0x0E ) { nkeynes@341: fprintf( f, "LINK %08X\n", entry &0x7FFFFF ); nkeynes@341: } else { nkeynes@341: uint32_t *polygon = (uint32_t *)(video_base + poly_bank + ((entry & 0x000FFFFF) << 2)); nkeynes@341: int vertex_length = (entry >> 21) & 0x07; nkeynes@341: int context_length = 3; nkeynes@351: if( (entry & 0x01000000) && (shadow_cfg==0) ) { nkeynes@341: context_length = 5; nkeynes@341: vertex_length *= 2 ; nkeynes@341: } nkeynes@341: vertex_length += 3; nkeynes@341: if( (entry & 0xE0000000) == 0x80000000 ) { nkeynes@341: /* Triangle(s) */ nkeynes@341: int strip_count = ((entry >> 25) & 0x0F)+1; nkeynes@341: for( i=0; i> 25) & 0x0F)+1; nkeynes@341: for( i=0; i>i) ) { nkeynes@341: last = i; nkeynes@341: } nkeynes@341: } nkeynes@341: fprintf( f, "POLY %08X %08X %08X\n", polygon[0], polygon[1], polygon[2] ); nkeynes@341: for( i=0; i> 28 == 0x0F ) { nkeynes@341: break; nkeynes@341: } else if( entry >> 28 == 0x0E ) { nkeynes@341: tile_list = (uint32_t *)(video_base + (entry&0x007FFFFF)); nkeynes@341: } else { nkeynes@341: render_print_polygon(f, entry); nkeynes@341: } nkeynes@341: } while( 1 ); nkeynes@341: } nkeynes@341: