From 64c033021aa8275f243ff568710f05fe08113c37 Mon Sep 17 00:00:00 2001 From: masscat Date: Sat, 21 Apr 2007 16:47:53 +0000 Subject: [PATCH] Change to software vertex transformation as NDS can change the ModelView matrix during primitives. Move the polygon attribute handling to the begin handler. --- desmume/src/opengl_collector_3Demu.c | 404 +++++++++++++++++++-------- 1 file changed, 294 insertions(+), 110 deletions(-) diff --git a/desmume/src/opengl_collector_3Demu.c b/desmume/src/opengl_collector_3Demu.c index 2e89b3c0d..9fb3f2d33 100644 --- a/desmume/src/opengl_collector_3Demu.c +++ b/desmume/src/opengl_collector_3Demu.c @@ -1,4 +1,4 @@ -/* $Id: opengl_collector_3Demu.c,v 1.8 2007-04-20 16:44:38 masscat Exp $ +/* $Id: opengl_collector_3Demu.c,v 1.9 2007-04-21 16:47:53 masscat Exp $ */ /* Copyright (C) 2006-2007 Ben Jaques, shash @@ -91,6 +91,24 @@ LOG( "%f, %f, %f, %f\n", matrix[12], matrix[13], matrix[14], matrix[15]) #define USE_BGR_ORDER 1 +/** + * Define this to use software vertex transformation. + * The NDS can handle commands to change the modelview matrix during + * primitive definitions (between the begin and end). OpenGL does + * not like this. + * When this is defined the Modelview matrix will be left as the + * identity matrix and vertices are transformed before being passed + * to OpenGL. + */ +#define USE_SOFTWARE_VERTEX_TRANSFORM 1 + +/** + * Define this to enable Alpha Blending emulation. + * How the NDS renders transulcent polygons (order) is not fully understood + * so some polygon may not be rendered or rendered incorrectly. + */ +#define ENABLE_ALPHA_BLENDING 1 + /** the largest number of parameters used by any command */ #define MAX_NUMBER_OF_PARMS 32 @@ -158,6 +176,11 @@ static int t_texture_coord = 0, s_texture_coord = 0; static GLint colorRGB[4] = { 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff}; static float cur_vertex[3] = {0.0f, 0.0f, 0.0f}; +static u32 alpha_function = 0; + +/** the current polygon attribute */ +static u32 current_polygon_attr = 0; + /** flag set when a primitive is being defined */ static int inside_primitive = 0; /** the type of primitive being defined */ @@ -285,6 +308,15 @@ set_gl_matrix_mode( int mode) { } } +static void +loadMatrix( float *matrix) { +#ifdef USE_SOFTWARE_VERTEX_TRANSFORM + if ( current_matrix_mode == 0) +#endif + glLoadMatrixf( matrix); +} + + static void SetupTexture (unsigned int format, unsigned int palette) { if(format == 0) // || disableTexturing) @@ -303,7 +335,7 @@ SetupTexture (unsigned int format, unsigned int palette) { unsigned short param2 = (unsigned short)((format>>16)&0xF); unsigned int imageSize = sizeX*sizeY; unsigned int paletteSize = 0; - unsigned int palZeroTransparent = (1-((format>>29)&1))*255; // shash: CONVERT THIS TO A TABLE :) + unsigned int palZeroTransparent = BIT29(format) ? 0 : 255; unsigned int x=0, y=0; if (mode == 0) @@ -375,6 +407,10 @@ SetupTexture (unsigned int format, unsigned int palette) { dst[1] = (unsigned char)((c & 0x3E0)>>2); dst[2] = (unsigned char)((c & 0x7C00)>>7); dst[3] = ((alpha<<2)+(alpha>>1))<<3; + if ( dst[3] != 0) { + /* full range alpha */ + dst[3] |= 0x7; + } } break; @@ -577,6 +613,10 @@ SetupTexture (unsigned int format, unsigned int palette) { dst[1] = (unsigned char)((c & 0x3E0)>>2); dst[2] = (unsigned char)((c & 0x7C00)>>7); dst[3] = (adr[x]&0xF8); + if ( dst[3] != 0) { + /* full range alpha */ + dst[3] |= 0x7; + } dst += 4; } break; @@ -683,17 +723,26 @@ SetupTexture (unsigned int format, unsigned int palette) { // S Coordinate options if (!BIT16(format)) glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); - else - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + else { + if ( BIT18(format)) { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_MIRRORED_REPEAT); + } + else { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT); + } + } // T Coordinate options if (!BIT17(format)) glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); - else - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); - - //flipS = BIT18(format); - //flipT = BIT19(format); + else { + if ( BIT19(format)) { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_MIRRORED_REPEAT); + } + else { + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT); + } + } texCoordinateTransform = (format>>30); } @@ -716,17 +765,170 @@ setup_mode23_tex_coord( float *vertex) { static INLINE void setup_vertex( float *vertex) { +#ifdef USE_SOFTWARE_VERTEX_TRANSFORM + float pre_transformed_vertex[4]; + float transformed_vertex[4]; + float *model_matrix = mtxCurrent[1]; +#endif + LOG("vertex %f,%f,%f\n", vertex[0], vertex[1], vertex[2]); if (texCoordinateTransform == 3) - { + { setup_mode23_tex_coord( vertex); - } + } +#ifdef USE_SOFTWARE_VERTEX_TRANSFORM + /* + * Transform the vertex + */ + pre_transformed_vertex[0] = vertex[0]; + pre_transformed_vertex[1] = vertex[1]; + pre_transformed_vertex[2] = vertex[2]; + pre_transformed_vertex[3] = 1.0f; + transformed_vertex[0] = + pre_transformed_vertex[0] * model_matrix[0] + + pre_transformed_vertex[1] * model_matrix[4] + + pre_transformed_vertex[2] * model_matrix[8] + + pre_transformed_vertex[3] * model_matrix[12]; + transformed_vertex[1] = + pre_transformed_vertex[0] * model_matrix[1] + + pre_transformed_vertex[1] * model_matrix[5] + + pre_transformed_vertex[2] * model_matrix[9] + + pre_transformed_vertex[3] * model_matrix[13]; + transformed_vertex[2] = + pre_transformed_vertex[0] * model_matrix[2] + + pre_transformed_vertex[1] * model_matrix[6] + + pre_transformed_vertex[2] * model_matrix[10] + + pre_transformed_vertex[3] * model_matrix[14]; + transformed_vertex[3] = + pre_transformed_vertex[0] * model_matrix[3] + + pre_transformed_vertex[1] * model_matrix[7] + + pre_transformed_vertex[2] * model_matrix[11] + + pre_transformed_vertex[3] * model_matrix[15]; + + glVertex4fv( transformed_vertex); +#else glVertex3fv( vertex); +#endif } +static INLINE void +handle_polygon_attribute( u32 attr, u32 control) { + static const int texEnv[4] = { GL_MODULATE, GL_DECAL, GL_MODULATE, GL_MODULATE }; + static const int depthFunc[2] = { GL_LESS, GL_EQUAL }; + static const unsigned short map3d_cull[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; + u32 light_mask = attr & 0xf; + u32 cullingMask; + GLint colorAlpha; + + /* + * lighting + * (should be done at the normal?) + */ + if ( light_mask) { + if ( light_mask & 1) { + LOG("enabling light 0\n"); + glEnable (GL_LIGHT0); + } + else { + LOG("disabling light 0\n"); + glDisable(GL_LIGHT0); + } + if ( light_mask & 2) { + LOG("enabling light 1\n"); + glEnable (GL_LIGHT1); + } + else { + LOG("disabling light 1\n"); + glDisable(GL_LIGHT1); + } + if ( light_mask & 4) { + LOG("enabling light 2\n"); + glEnable (GL_LIGHT2); + } + else { + LOG("disabling light 2\n"); + glDisable(GL_LIGHT2); + } + if ( light_mask & 8) { + LOG("enabling light 3\n"); + glEnable (GL_LIGHT3); + } + else { + LOG("disabling light 3\n"); + glDisable(GL_LIGHT3); + } + + glEnable (GL_LIGHTING); + //glEnable (GL_COLOR_MATERIAL); + } + else { + LOG( "Disabling lighting\n"); + glDisable (GL_LIGHTING); + } + + /* + * texture environment + */ + glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texEnv[(attr & 0x30)>>4]); + + /* + * depth function + */ + glDepthFunc( depthFunc[BIT14(attr)]); + + /* + * Cull face + */ + cullingMask = (attr & 0xC0); + if (cullingMask != 0xC0) { + glEnable(GL_CULL_FACE); + glCullFace(map3d_cull[cullingMask>>6]); + } + else { + glDisable(GL_CULL_FACE); + } + + /* + * Alpha value, actually not well handled, 0 should be wireframe + * + * FIXME: How are translucent polygons rendered? + * some use of polygon ID? + */ + glDepthMask( GL_TRUE); + colorAlpha = (attr>>16) & 0x1F; + if ( colorAlpha != 0) { + colorAlpha = (colorAlpha << 26) | 0x3ffffff; +#if 0 + if ( colorAlpha != 0x7fffffff) { + if ( !BIT11( attr)) { + glDepthMask( GL_FALSE); + } + } +#endif + colorRGB[3] = colorAlpha; + glColor4iv (colorRGB); + } + + + /* + * Alpha blending + */ +#ifdef ENABLE_ALPHA_BLENDING + if ( BIT3(control)) { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable( GL_BLEND); + } + else { + glDisable( GL_BLEND); + } +#endif +} + + + static void process_begin_vtxs( struct render_state *state, const u32 *parms) { @@ -734,6 +936,29 @@ process_begin_vtxs( struct render_state *state, LOG("Begin: %s\n", primitive_type_names[prim_type]); + /* FIXME: ignoring shadow polygons for now */ + if ( ((current_polygon_attr >> 4) & 0x3) == 3) { + return; + } + + if( disp_3D_control & (1<<2)) + { + LOG("Alpha test enabled\n"); + glEnable(GL_ALPHA_TEST); + glAlphaFunc (GL_GREATER, (alpha_function&31)/31.f); + } + else + { + glDisable(GL_ALPHA_TEST); + } + + + /* + * Setup for the current polygon attribute + */ + handle_polygon_attribute( current_polygon_attr, disp_3D_control); + + /* setup the texture */ #if 0 glDisable (GL_TEXTURE_2D); @@ -794,100 +1019,19 @@ process_viewport( struct render_state *state, LOG("Viewport %d,%d,%d,%d\n", parms[0] & 0xff, (parms[0] >> 8) & 0xff, (parms[0] >> 16) & 0xff, (parms[0] >> 24) & 0xff); glViewport( (parms[0]&0xFF), ((parms[0]>>8)&0xFF), - ((parms[0]>>16)&0xFF), (parms[0]>>24)); + ((parms[0]>>16)&0xFF) + 1, (parms[0]>>24) + 1); } static void process_polygon_attr( struct render_state *state, const u32 *parms) { - static const int texEnv[4] = { GL_MODULATE, GL_DECAL, GL_MODULATE, GL_MODULATE }; - static const int depthFunc[2] = { GL_LESS, GL_EQUAL }; - static const unsigned short map3d_cull[4] = {GL_FRONT_AND_BACK, GL_FRONT, GL_BACK, 0}; - u32 light_mask = parms[0] & 0xf; - u32 cullingMask; - u32 colorAlpha; - LOG("polygon attr %08x\n", parms[0]); /* - * lighting + * Save this until the next begin */ - if ( light_mask) { - if ( light_mask & 1) { - LOG("enabling light 0\n"); - glEnable (GL_LIGHT0); - } - else { - LOG("disabling light 0\n"); - glDisable(GL_LIGHT0); - } - if ( light_mask & 2) { - LOG("enabling light 1\n"); - glEnable (GL_LIGHT1); - } - else { - LOG("disabling light 1\n"); - glDisable(GL_LIGHT1); - } - if ( light_mask & 4) { - LOG("enabling light 2\n"); - glEnable (GL_LIGHT2); - } - else { - LOG("disabling light 2\n"); - glDisable(GL_LIGHT2); - } - if ( light_mask & 8) { - LOG("enabling light 3\n"); - glEnable (GL_LIGHT3); - } - else { - LOG("disabling light 3\n"); - glDisable(GL_LIGHT3); - } - - glEnable (GL_LIGHTING); - //glEnable (GL_COLOR_MATERIAL); - } - else { - LOG( "Disabling lighting\n"); - glDisable (GL_LIGHTING); - } - - /* - * texture environment - */ - glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, texEnv[(parms[0]&0x30)>>4]); - - /* - * depth function - */ - glDepthFunc( depthFunc[BIT14(parms[0])]); - - /* - * Cull face - */ - cullingMask = (parms[0] & 0xC0); - if (cullingMask != 0xC0) { - glEnable(GL_CULL_FACE); - glCullFace(map3d_cull[cullingMask>>6]); - } - else { - glDisable(GL_CULL_FACE); - } - - /* - * Alpha value, actually not well handled, 0 should be wireframe - */ - colorAlpha = ((parms[0]>>16)&0x1F)<<26; - if ( colorAlpha != 0) { - colorRGB[3] = colorAlpha; - glColor4iv (colorRGB); - } - - - + current_polygon_attr = parms[0]; } static void @@ -940,6 +1084,20 @@ process_dif_amb( struct render_state *state, LOG("dif amb %08x\n", parms[0]); + if ( diffuse[0] != 0) + diffuse[0] |= 0x3ffffff; + if ( diffuse[1] != 0) + diffuse[1] |= 0x3ffffff; + if ( diffuse[2] != 0) + diffuse[2] |= 0x3ffffff; + + if ( ambient[0] != 0) + ambient[0] |= 0x3ffffff; + if ( ambient[1] != 0) + ambient[1] |= 0x3ffffff; + if ( ambient[2] != 0) + ambient[2] |= 0x3ffffff; + if (BIT15(parms[0])) { colorRGB[0] = diffuse[0]; @@ -966,6 +1124,21 @@ process_spe_emi( struct render_state *state, ((parms[0]>>26)&0x1F) << 26, 0x7fffffff }; + if ( specular[0] != 0) + specular[0] |= 0x3ffffff; + if ( specular[1] != 0) + specular[1] |= 0x3ffffff; + if ( specular[2] != 0) + specular[2] |= 0x3ffffff; + + if ( emission[0] != 0) + emission[0] |= 0x3ffffff; + if ( emission[1] != 0) + emission[1] |= 0x3ffffff; + if ( emission[2] != 0) + emission[2] |= 0x3ffffff; + + LOG("spe emi %08x\n", parms[0]); glMaterialiv (GL_FRONT_AND_BACK, GL_SPECULAR, specular); @@ -1086,7 +1259,7 @@ process_mtx_pop( struct render_state *state, } if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } static void @@ -1112,7 +1285,7 @@ process_mtx_restore( struct render_state *state, } if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } static void @@ -1146,7 +1319,7 @@ process_mtx_load_4x4( struct render_state *state, mtxCurrent[current_matrix_mode][14], mtxCurrent[current_matrix_mode][15]); if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } static void @@ -1193,7 +1366,7 @@ process_mtx_load_4x3( struct render_state *state, mtxCurrent[current_matrix_mode][14], mtxCurrent[current_matrix_mode][15]); if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } @@ -1218,10 +1391,10 @@ process_mtx_trans( struct render_state *state, if ( current_matrix_mode == 2) { LOG_MATRIX( mtxCurrent[1]); - glLoadMatrixf( mtxCurrent[1]); + loadMatrix( mtxCurrent[1]); } else if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } static void @@ -1244,9 +1417,9 @@ process_mtx_scale( struct render_state *state, LOG("scale %f,%f,%f\n", scale[0], scale[1], scale[2]); if ( current_matrix_mode == 2) - glLoadMatrixf( mtxCurrent[1]); + loadMatrix( mtxCurrent[1]); else if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } static void @@ -1266,9 +1439,9 @@ process_mtx_mult_4x4( struct render_state *state, MatrixMultiply (mtxCurrent[1], mult_matrix); if ( current_matrix_mode == 2) - glLoadMatrixf( mtxCurrent[1]); + loadMatrix( mtxCurrent[1]); else if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } static void @@ -1300,9 +1473,9 @@ process_mtx_mult_4x3( struct render_state *state, MatrixMultiply (mtxCurrent[1], mult_matrix); if ( current_matrix_mode == 2) - glLoadMatrixf( mtxCurrent[1]); + loadMatrix( mtxCurrent[1]); else if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } static void @@ -1333,9 +1506,9 @@ process_mtx_mult_3x3( struct render_state *state, MatrixMultiply (mtxCurrent[1], mult_matrix); if ( current_matrix_mode == 2) - glLoadMatrixf( mtxCurrent[1]); + loadMatrix( mtxCurrent[1]); else if ( current_matrix_mode < 3) - glLoadMatrixf( mtxCurrent[current_matrix_mode]); + loadMatrix( mtxCurrent[current_matrix_mode]); } static void @@ -1344,6 +1517,14 @@ process_colour( struct render_state *state, colorRGB[0] = (parms[0] & 0x1f) << 26; colorRGB[1] = ((parms[0] >> 5) & 0x1f) << 26; colorRGB[2] = ((parms[0] >> 10) & 0x1f) << 26; + + if ( colorRGB[0] != 0) + colorRGB[0] |= 0x3ffffff; + if ( colorRGB[1] != 0) + colorRGB[1] |= 0x3ffffff; + if ( colorRGB[2] != 0) + colorRGB[2] |= 0x3ffffff; + LOG("colour %08x,%08x,%08x (%08x)\n", colorRGB[0], colorRGB[1], colorRGB[2], parms[0]); @@ -1444,7 +1625,10 @@ static void process_alpha_function( struct render_state *state, const u32 *parms) { LOG("Alpha function %08x\n", parms[0]); - glAlphaFunc (GL_GREATER, (parms[0]&31)/31.f); + /* + * Save for later + */ + alpha_function = parms[0]; } static void